angular / angular-cli

CLI tool for Angular
https://cli.angular.dev
MIT License
26.78k stars 11.98k forks source link

`urlRoot` in `karma.conf.js` can't be set to anything other than the default `/` #22132

Open colossatr0n opened 3 years ago

colossatr0n commented 3 years ago

🐞 Bug report

Command (mark with an x)

Is this a regression?

No.

Description

Can't set urlRoot in karma.conf.js to anything other than "/" because:

Angular CLI uses custom context file, which leads to this bug. It adds <base href="/">, which forces context.html to request http://localhost:9876/context.js instead of http://localhost:9876/karma/context.js.

which is described in detail in this issue: https://github.com/karma-runner/karma/issues/3357#issuecomment-634630974.

πŸ”¬ Minimal Reproduction

Run ng test with a karma.conf.js that contains a urlRoot set to anything but /:

{
    ...,
    urlRoot: "newBase"
}

πŸ”₯ Exception or Error

The error that is logged is the following:

09 11 2021 23:25:29.766:WARN [web-server]: 404: /_karma_webpack_/context.js

🌍 Your Environment


Angular CLI: 11.2.0
Node: 14.18.0
OS: darwin x64

Angular: 11.2.14
... common, compiler, compiler-cli, core, forms, localize
... platform-browser, platform-browser-dynamic, router, upgrade
Ivy Workspace: Yes

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1102.0
@angular-devkit/build-angular   0.1102.0
@angular-devkit/core            11.2.14
@angular-devkit/schematics      11.2.14
@angular/animations             12.2.8
@angular/cdk                    11.2.13
@angular/cli                    11.2.0
@schematics/angular             11.2.14
@schematics/update              0.1102.0
rxjs                            6.6.7
typescript                      4.1.6

alan-agius4 commented 3 years ago

Hi @colossatr0n,

Can you please share the use-case of why do you need to set a custom urlRoot?

colossatr0n commented 3 years ago

Yes, I'll try my best to explain it.

TL;DR: Being able to specify urlRoot allows for pact testing Angular service requests that can't otherwise be tested when the application's base URL is set by Tomcat.

I'm currently using the karma-pact plugin to run pact tests through karma. The way the application is set up is like this:

  1. angular-cli is used to compile the UI.
  2. Tomcat is used to serve the contents of the dist directory.
  3. Tomcat sets the application's base URL from / to /someBaseUrl.

In the Angular services, I have to make sure that all request URLs don't start with /:

// When the application is run through Tomcat, this URL becomes `/someBaseUrl/request/url` <--- correct
this.http.get<any>("request/url")

// If the URL is incorrectly prepended with `/`, this URL becomes `/request/url` <--- incorrect
this.http.get<any>("/request/url")

When testing locally using ng serve, using either URL works since both get proxied to /someBaseUrl/request/url. This isn't the case when running the application through Tomcat since there's no proxy involved.

A pact test is able to catch an error like this, but with the way the application is architected, it can't. The reasons why this doesn't work are:

  1. Pact test requests are made from the karma server localhost:9876
  2. Regardless of if the Angular service prepends the request URL with /, the result is the same:
localhost:9876 + request/url =  localhost:9876/request/url
localhost:9876 + /request/url = localhost:9876/request/url <--- pact test won't detect that the request was prepended with `/`

To the pact test, everything looks fine, but when the application is deployed and tested, any requests prepended with / will result in 404s.

Being able to specify a base for the karma server would allow the pact tests to properly detect the difference:

localhost:9876/someBaseUrl + request/url =  localhost:9876/someBaseUrl/request/url
localhost:9876/someBaseUrl + /request/url = localhost:9876/request/url <--- pact test will detect this as a failure
alan-agius4 commented 3 years ago

Hi @colossatr0n,

Thanks for the above explanation.

I am trying to understand a bit better your test setup. When running ng test, the application is served from memory similar to ng serve. Therefore, I am a bit confused by what you mean you are serving the contents of the dist directory using Tomcat for testing.

In your karma.conf.js you can easily setup a proxy to redirect your HTTP requests.

Example:

module.exports = (config) {
  config.set({
    // ... other configurations
    proxies: {
      'request/': 'http://127.0.0.1:1234/someBaseUrl/request/' // NB: this target is your pact server.
    }
  });
};   

For more information about proxies in Karma see https://karma-runner.github.io/6.3/config/configuration-file.html#proxies.

colossatr0n commented 3 years ago

Sorry, the explanation for serving the contents of the dist folder was just to show how the application is served. Tomcat isn't used for running the tests.

The issue with using the proxy with a urlRoot of / is that a request made to /request or request results in a successful proxied request and I need /request to not be proxied. If I could set the urlRoot, I could use the proxy like so:

module.exports = (config) {
  config.set({
    // ... other configurations
    proxies: {
      '/someBaseUrl/request/': 'http://127.0.0.1:1234/someBaseUrl/request/' 
    }
  });
};   

With a ulrRoot of someBaseUrl, a request to /request (localhost:9876/request) wouldn't get proxied, while a request to request (localhost:9876/someBaseUrl/request) would get proxied.