Global variables in Karma test runner

2019-01-23 01:32发布

I have a global variable defined in my main template, which I use to store information bits from the back end, such as the environment context path. I can't move that variable inside a service.

How can I expose that variable to Karma when I run the unit tests?

3条回答
萌系小妹纸
2楼-- · 2019-01-23 01:44

You either declare that global variable within your test file:

var global = "something";

describe('Your test suit', function() {
...
});

or add a Javascript file where it's defined to your karma.conf.js file:

// list of files / patterns to load in the browser
files: [
   ...,
   'file-containing-the-global-variable.js'
],
查看更多
乱世女痞
3楼-- · 2019-01-23 02:02

The first solution didn't work for me in Angular 2.1.x. It simply would not recognize the variable in my imported service. What I had to do was put my environment variable in my karma-test-shim.js file and remove var so it would be globally available.

Mine looks like this:

Error.stackTraceLimit = Infinity;

require('core-js/es6');
require('reflect-metadata');

require('zone.js/dist/zone');
require('zone.js/dist/long-stack-trace-zone');
require('zone.js/dist/proxy'),
require('zone.js/dist/sync-test'),
require('zone.js/dist/jasmine-patch');
require('zone.js/dist/async-test');
require('zone.js/dist/fake-async-test');

// Add environment variables here so that tests will inject them in source code
API_URL = 'http://localhost:8080/api/';

var appContext = require.context('../src', true, /\.spec\.ts/);

appContext.keys().forEach(appContext);

var testing = require('@angular/core/testing');
var browser = require('@angular/platform-browser-dynamic/testing');

testing.TestBed.initTestEnvironment(
    browser.BrowserDynamicTestingModule,
    browser.platformBrowserDynamicTesting()
);
查看更多
姐就是有狂的资本
4楼-- · 2019-01-23 02:07

If you are coming from Angular 2+ the only way I found that works is to create the variable or object globally using window:

Google Recapthca Loaded from a script:

<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>

In this example a call to the google Recaptcha will create a global variable called grecaptcha.

In our component we decide to render a new Google Recaptcha. Of course since we do not declare grecaptcha we need to use declare var to say hey I promise it is declared somewhere:

declare var grecaptcha;

private CreateGoogleCaptcha() {
  grecaptcha.render('recaptcha', {
    sitekey: this.siteKey,
    callback: this.GoogleCaptchaCallback,
    badge: 'inline'
  });
}

private GoogleCaptchaCallback(token) {
   // Handle Callback Logic
}

Now that our function works we decide to run a test but of course we would like to mock our grecaptcha as we don't have control over it. So we name our global variable we would like to create and add the functions we would like:

beforeEach(() => {
  fixture = TestBed.createComponent(GoogleRecaptchaComponent);
  component = fixture.componentInstance;

  window['grecaptcha'] = {
    render() {
      console.log('mocked global variable and function');
    }
  }
}

Update:

Creating the global variable in the beforeEach is fine but what about when it has some sort of callback function such as above that calls a function from your component? Easy enough we just move the login to our test and in our mock we set it to our components function:

it('should ', () => {
  window['grecaptcha'] = {
    render: function() { GoogleRecaptchaComponent['GoogleCaptchaCallback']('token'); }
  };

  spyOn<any>(GoogleRecaptchaComponent, 'GoogleCaptchaCallback');

  GoogleRecaptchaComponent['CreateGoogleCaptcha']();
  expect(GoogleRecaptchaComponent['GoogleCaptchaCallback']).toHaveBeenCalled();
});

Note: spyOn<any>: The <any> is used so we can refence without error the function because it is private, otherwise we will get a typescript error;

查看更多
登录 后发表回答