title: Mocking an environment in Angular with Jasmine
body: <p>I'm still learning how to write tests for angular using Karma/Jasmine. I want to return false for the environment's isDebugMode. It works obviously when I change the code for it but how do I write a test for that? I have set up some tests trying figure out how to mock the environment. But none seem to work the way I think it does. I was wondering if someone could explain why these are returning the values they do. </p>
  
  <pre><code>import { TestBed, inject } from '@angular/core/testing';
  import { LoggerService } from './logger.service';
  import { environment } from '../environments/environment';
  import { mockEnvironment} from '../environments/environment.mock';
  
  describe('Test', () =&gt; {
  
    beforeEach(() =&gt; {
  
      spyOn(console, 'error');
      spyOn(console, 'warn');
  
      TestBed.configureTestingModule({
        providers: [ LoggerService ]
      });
  
  
    });
  
    it('should be created',
      inject([LoggerService],
        (service: LoggerService) =&gt; {
          expect(service).toBeTruthy();
        }));
  
    it('should always work', function() {
      expect(true).toBe(true);
    });
  
    it('is the mocked environment returning false', function() {
      spyOn(mockEnvironment, 'isDebugMode');
      expect(mockEnvironment.isDebugMode).toEqual(false);
    });
  
    it('is the environment returning true', function() {
      spyOn(environment, 'isDebugMode');
      expect(environment.isDebugMode).toEqual(true);
    });
  
    it('enclosing in function makes everything true, why?',
      function () {
      spyOn(environment, 'isDebugMode').and.returnValue(false);
      inject([LoggerService],
        (service: LoggerService) =&gt; {
          const type = 'warn';
          const message = 'This message';
          service.log(type, message);
  
          expect(console.warn).not.toHaveBeenCalled(); // this does not seem to matter
        });
       }
    );
    it('enclosing in function makes everything true, why?',
      function () {
        spyOn(environment, 'isDebugMode').and.returnValue(false);
        inject([LoggerService],
          (service: LoggerService) =&gt; {
            const type = 'warn';
            const message = 'This message';
            service.log(type, message);
  
            expect(console.warn).toHaveBeenCalled(); // this does not seem to matter
          });
      }
    );
    it('should show up if isDebugMode is true',
      inject([LoggerService],
        (service: LoggerService) =&gt; {
          const type = 'warn';
          const message = 'This message';
  
          service.log(type, message);
          expect(console.warn).toHaveBeenCalled(); // this works
        })
    );
    it('should not show up if isDebugMode is false using spy with return value',
        inject([LoggerService],
          (service: LoggerService) =&gt; {
            const type = 'warn';
            const message = 'This message';
            spyOn(environment, 'isDebugMode').and.returnValue(false);
  
            service.log(type, message);
            expect(console.warn).not.toHaveBeenCalled(); // this is does not work
          })
    );
    it('should not show up if isDebugMode is false using spy with callfake',
      inject([LoggerService],
        (service: LoggerService) =&gt; {
          const type = 'warn';
          const message = 'This message';
          spyOn(environment, 'isDebugMode').and.callFake(mockEnvironment.isDebugMode); // boolean is not a function
  
          service.log(type, message);
          expect(console.warn).not.toHaveBeenCalled(); // this is does not work
        })
    );
    it('should not show up if isDebugMode is false using spy with stub',
      inject([LoggerService],
        (service: LoggerService) =&gt; {
          const type = 'warn';
          const message = 'This message';
          spyOn(environment, 'isDebugMode').and.stub();
  
          service.log(type, message);
          expect(console.warn).not.toHaveBeenCalled(); // this is does not work
        })
    );
  
  
  });
  </code></pre>
  
  <p>These are the files I'm trying to test: 
  logger.service.ts</p>
  
  <pre><code>import { Injectable } from '@angular/core';
  import { environment } from '../environments/environment';
  
  const isDebugMode = environment.isDebugMode;
  
  @Injectable()
  export class LoggerService {
  
    log(type: string, message?: any): void {
      if (type === 'info' || type === 'warn' || type === 'debug' || type === 'error' || type === 'log') {
        const logFn: Function = (console)[type];
        if (isDebugMode) {
          logFn.apply(console, [message]);
        }
      } else {
        console.error('Logger type incorrect');
      }
    }
  }
  </code></pre>
  
  <p>With the environment.ts</p>
  
  <pre><code>export const environment = {
    production: false,
    hmr: false,
    isDebugMode: true
  };
  </code></pre>
  
  <p>and environment.mock.ts</p>
  
  <pre><code>export const MockEnvironment = {
    production: false,
    hmr: false,
    isDebugMode: false
  };
  </code></pre>
  
  <p>Test</p>
  
  <ul>
  <li>should be created - pass</li>
  <li>should always work - pass</li>
  <li>is the mocked environment returning false - fail</li>
  <li>is the environment returning true - fail</li>
  <li>enclosing in function makes everything true, why? - pass</li>
  <li>enclosing in function makes everything true, why? - pass</li>
  <li>should show up if isDebugMode is true - pass</li>
  <li>should not show up if isDebugMode is false using spy with return value - fail</li>
  <li>should not show up if isDebugMode is false using spy with callfake - fail</li>
  <li>should not show up if isDebugMode is false using spy with stub - fail</li>
  </ul>