@angular/common/http/testing#HttpTestingController TypeScript Examples

The following examples show how to use @angular/common/http/testing#HttpTestingController. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: utility.service.spec.ts    From dayz-server-manager with MIT License 7 votes vote down vote up
describe('UtilityService', () => {
    let utilityService: UtilityService;

    let httpClient: HttpClient;
    let httpTestingController: HttpTestingController;

    beforeEach(() => {
        TestBed.configureTestingModule({
            imports: [HttpClientTestingModule],
            providers: [UtilityService],
        });
        utilityService = TestBed.inject(UtilityService);

        httpClient = TestBed.inject(HttpClient);
        httpTestingController = TestBed.inject(HttpTestingController);
    });

    describe('getUtility$', () => {
        it('should return Observable<Utility>', () => {
            utilityService.version$.pipe(take(1)).subscribe(response => {
                expect(response).toEqual('a.b.c');
            });

            const req = httpTestingController.expectOne('/assets/version');
            expect(req.request.method).toEqual('GET');

            req.flush('a.b.c');
            httpTestingController.verify();
        });
    });
});
Example #2
Source File: expect-request.ts    From s-libs with MIT License 6 votes vote down vote up
function matchRequest(
  ctx: AngularContext,
  options: MatchOptions,
): SlTestRequest<HttpBody> {
  const controller = ctx.inject(HttpTestingController);
  matchCount = 0;
  pendingRequests = [];
  return new SlTestRequest(
    controller.expectOne((req) => {
      pendingRequests.push(req);
      const found = isMatch(req, options);
      if (found) {
        ++matchCount;
      }
      return found;
    }),
  );
}
Example #3
Source File: angular-context.spec.ts    From s-libs with MIT License 6 votes vote down vote up
describe('AngularContext class-level doc example', () => {
  // This is the class we will test.
  @Injectable({ providedIn: 'root' })
  class MemoriesService {
    constructor(private httpClient: HttpClient) {}

    getLastYearToday(): Observable<any> {
      const datetime = new Date();
      datetime.setFullYear(datetime.getFullYear() - 1);
      const date = datetime.toISOString().split('T')[0];
      return this.httpClient.get(`http://example.com/post-from/${date}`);
    }
  }

  describe('MemoriesService', () => {
    // Tests should have exactly 1 variable outside an "it": `ctx`.
    let ctx: AngularContext;
    beforeEach(() => {
      ctx = new AngularContext();
    });

    it('requests a post from 1 year ago', () => {
      // Before calling `run`, set up any context variables this test needs.
      ctx.startTime = new Date('2004-02-16T10:15:00.000Z');

      // Pass the test itself as a callback to `run()`.
      ctx.run(() => {
        const httpBackend = ctx.inject(HttpTestingController);
        const myService = ctx.inject(MemoriesService);

        myService.getLastYearToday().subscribe();

        httpBackend.expectOne('http://example.com/post-from/2003-02-16');
      });
      expect().nothing();
    });
  });
});
Example #4
Source File: auth.interceptor.spec.ts    From dating-client with MIT License 5 votes vote down vote up
describe('Auth Interceptor', () => {
  let store: MockStore;
  let httpClient: HttpClient;
  let httpMock: HttpTestingController;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [ HttpClientTestingModule ],
      providers: [ AuthInterceptorProvider, provideMockStore() ]
    });

    store = TestBed.inject(MockStore);
    httpClient = TestBed.inject(HttpClient);
    httpMock = TestBed.inject(HttpTestingController);
  });

  afterEach(() => httpMock.verify());

  it('should add an Auth header to request if the token is valid(exists)', done => {
    store.overrideSelector(selectAuthToken, 'TestToken');
    store.refreshState();

    httpClient.get('/api').subscribe(() => done());

    const req = httpMock.expectOne('/api');

    expect(req.request.headers.has('Authorization')).toEqual(true);
    expect(req.request.headers.get('Authorization')).toBe('Bearer TestToken');

    req.flush({});
  });

  it('should not add an Auth header if the token is undefined', done => {
    store.overrideSelector(selectAuthToken, undefined);
    store.refreshState();

    httpClient.get('/api').subscribe(() => done());

    const req = httpMock.expectOne('/api');

    expect(req.request.headers.has('Authorization')).toEqual(false);

    req.flush({});
  });

});
Example #5
Source File: angular-context.ts    From s-libs with MIT License 5 votes vote down vote up
/**
   * Runs post-test verifications. This base implementation runs [HttpTestingController.verify]{@linkcode https://angular.io/api/common/http/testing/HttpTestingController#verify} and {@linkcode MockErrorHandler.verify}. Unlike {@linkcode #cleanUp}, it is OK for this method to throw an error to indicate a violation.
   */
  protected verifyPostTestConditions(): void {
    this.inject(HttpTestingController).verify();
    this.inject(MockErrorHandler).verify();
  }
Example #6
Source File: auth.service.spec.ts    From dating-client with MIT License 5 votes vote down vote up
describe('Auth Service', () => {
  let authService: AuthService;
  let httpMock: HttpTestingController;
  const apiUrl = '/api';

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [ HttpClientTestingModule ],
      providers: [
        { provide: API_URL, useValue: apiUrl },
        AuthService
      ]
    });

    authService = TestBed.inject(AuthService);
    httpMock = TestBed.inject(HttpTestingController);
  });

  afterEach(() => httpMock.verify());

  it('should be created', () => {
    expect(authService).toBeTruthy();
  });


  describe('register method', () => {
    const payload: RegisterUserPayload = {
      username: 'test', birthday: new Date(),
      city: 'T', country: 'T', gender: 'Male',
      knownAs: 'T', password: 'TTTTT'
    };

    it('should return Observable<unknown>', () => {
      authService.register(payload).subscribe(res => {
        expect(res).toBe({});
      });

      const path = `${ apiUrl }/auth/register`;

      const req = httpMock.expectOne(path);
      expect(req.request.url).toBe(path);
      expect(req.request.method).toEqual('POST');

      req.flush({});
    });
  });

  describe('login method', () => {
    const credentials: LoginPayload = { username: 'test',  password: 'TTTTT' };
    const response: AuthUser = { id: 1, name: 't', token: 't' };
    it('should return Observable<LoginResponse>', () => {
      authService.login(credentials).subscribe(res => {
        expect(res).toBe(response);
      });

      const path = `${ apiUrl }/auth/login`;

      const req = httpMock.expectOne(path);
      expect(req.request.url).toBe(path);
      expect(req.request.method).toEqual('POST');

      req.flush(response);
    });
  });


});
Example #7
Source File: records-metrics.component.spec.ts    From geonetwork-ui with GNU General Public License v2.0 5 votes vote down vote up
describe('RecordsMetricsComponent', () => {
  let component: RecordsMetricsComponent
  let fixture: ComponentFixture<RecordsMetricsComponent>
  let httpMock: HttpTestingController

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [RecordsMetricsComponent],
      imports: [
        UiSearchModule,
        TranslateModule.forRoot(),
        HttpClientTestingModule,
      ],
    }).compileComponents()
    httpMock = TestBed.inject(HttpTestingController)
  })

  beforeEach(() => {
    fixture = TestBed.createComponent(RecordsMetricsComponent)
    component = fixture.componentInstance
  })

  it('should create', () => {
    fixture.detectChanges()
    expect(component).toBeTruthy()
  })

  describe('fetching record counts', () => {
    it('parses the aggregation buckets', () => {
      component.field = 'myfield'
      component.count = 4
      component.queryString = '+filter=abcd'
      fixture.detectChanges()

      let results = null
      component.results$.subscribe((value) => (results = value))
      const req = httpMock.expectOne((req) => req.url.indexOf(`_search`) > -1)
      expect(JSON.parse(req.request.body)).toMatchObject({
        query: { query_string: { query: '+filter=abcd' } },
        aggs: {
          results: {
            terms: {
              field: 'myfield',
              size: 4,
            },
          },
        },
      })
      req.flush(aggsOnlyFixture)

      expect(results.length).toBe(
        aggsOnlyFixture.aggregations.results.buckets.length
      )
    })

    afterEach(() => {
      httpMock.verify()
    })
  })
})
Example #8
Source File: file.translate.loader.spec.ts    From geonetwork-ui with GNU General Public License v2.0 5 votes vote down vote up
describe('FileTranslateLoader', () => {
  let loader: FileTranslateLoader
  let httpController: HttpTestingController

  beforeEach(() => {
    fetchMock.reset()
    jest.spyOn(AppConfig, 'getCustomTranslations')
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
    })
    loader = new FileTranslateLoader(
      TestBed.inject(HttpClient),
      './assets/i18n/'
    )
    httpController = TestBed.inject(HttpTestingController)
  })

  it('should be created', () => {
    expect(loader).toBeTruthy()
  })

  describe('#getTranslation', () => {
    const EN = {
      'first.label': 'First Label.',
      'second.label': 'Second Label.',
    }
    const FR = {
      'first.label': '',
      'second.label': 'Deuxième libellé.',
    }
    describe('without app config', () => {
      it('uses only 2 letter code (ignore regional code)', () => {
        loader.getTranslation('en_US').subscribe(() => {}) // eslint-disable-line
        const req = httpController.expectOne('./assets/i18n/en.json')
        req.flush(EN)
      })
      it('filters out empty translations', () => {
        let translations
        loader
          .getTranslation('fr')
          .subscribe((result) => (translations = result))
        const req = httpController.expectOne('./assets/i18n/fr.json')
        req.flush(FR)
        expect(translations).toEqual({
          'second.label': 'Deuxième libellé.',
        })
      })
      it('does not check custom translations', () => {
        expect(AppConfig.getCustomTranslations).not.toHaveBeenCalled()
      })
    })
    describe('with app config', () => {
      beforeEach(async () => {
        fetchMock.get('end:default.toml', () => CONFIG_WITH_TRANSLATIONS)
        await loadAppConfig()
      })
      it('includes translations', () => {
        let translations
        loader
          .getTranslation('fr')
          .subscribe((result) => (translations = result))
        const req = httpController.expectOne('./assets/i18n/fr.json')
        req.flush(FR)
        expect(translations).toEqual({
          'second.label': 'Deuxième libellé.',
          'my.sample.text': 'Un bon exemple de texte.',
          'my.quoted.text': 'du texte entre guillements.',
        })
      })
    })
    afterEach(() => {
      httpController.verify()
    })
  })
})
Example #9
Source File: http.service.spec.ts    From aws-power-tuner-ui with Apache License 2.0 5 votes vote down vote up
describe('HttpService', () => {
  let httpTestingController: HttpTestingController;
  let service: HttpService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [HttpService],
      imports: [HttpClientTestingModule]
    });

    httpTestingController = TestBed.get(HttpTestingController);
    service = TestBed.get(HttpService);
  });

  afterEach(() => {
    httpTestingController.verify();
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });

  it('should post to power tuner endpoint to start with the payload and return a token', () => {
    const mockTuner = {
      executionToken: 'Test-Token'
    };
    service.performPowerTunerStepFunction({} as TunerPayload)
      .subscribe(res => {
        expect(res.executionToken).toEqual(mockTuner.executionToken);
      });
    const req = httpTestingController.expectOne('http://localhost:8080/power-tuner');
    expect(req.request.method).toEqual('POST');
    req.flush(mockTuner);
  });

  it('should post to pwoer tuner result endpoint to fetch the result', () => {
    const mockTunerResult = {
      status: 'SUCCEEDED',
      output: 'Test-output'
    };
    service.fetchPowerTunerStepFunction({} as PowerTunerToken)
      .subscribe(res => {
        expect(res.status).toEqual(mockTunerResult.status);
        expect(res.output).toEqual(mockTunerResult.output);
      });
    const req = httpTestingController.expectOne('http://localhost:8080/power-tuner/result');
    expect(req.request.method).toEqual('POST');
    req.flush(mockTunerResult);
  });
});
Example #10
Source File: home.component.spec.ts    From ledge with Mozilla Public License 2.0 5 votes vote down vote up
describe('HomeComponent', () => {
  let component: HomeComponent;
  let fixture: ComponentFixture<HomeComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        SharedModule,
        PeriodicTableModule,
        RouterTestingModule,
        HttpClientTestingModule,
        TranslateModule.forRoot({
          loader: {
            provide: TranslateLoader,
            useClass: TranslateFakeLoader,
          },
        }),
      ],
      declarations: [HomeComponent],
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(HomeComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('should update category', () => {
    const category = 'sourceMgr';

    component.setCurrentAtomCategory(category);

    expect(component.category).toBe(category);
  });

  it('should get data', () => {
    inject([HttpTestingController], (httpMock: HttpTestingController) => {
      component.ngAfterViewInit();

      const fisrt = httpMock.expectOne('./assets/periodic-table.json');
      const req = httpMock.expectOne(
        'https://api.github.com/repos/phodal/ledge/contributors'
      );
      expect(req.request.method).toEqual('GET');
      req.flush([]);

      httpMock.verify();
    });
  });
});
Example #11
Source File: bot-response.service.spec.ts    From mysteryofthreebots with Apache License 2.0 4 votes vote down vote up
describe('BotResponseService', () => {
  beforeEach(() => TestBed.configureTestingModule({
    imports: [
      HttpClientTestingModule,
    ],
  }));

  it('should be created', () => {
    const service: BotResponseService = TestBed.get(BotResponseService);
    expect(service).toBeTruthy();
  });

  describe('getResponse', () => {
    it('should return a matching query', inject(
      [
        HttpTestingController,
        BotResponseService,
      ],
      async (httpMock: HttpTestingController, service: BotResponseService) => {
        const loadPromise = service.loadModels();
        const matches = httpMock.match(() => true);
        const model = await use.load();
        const queryKey = JSON.stringify(['Who is there?']);
        const embedding = await model.embed(['Who is there?']);
        const embeddingArrays = await embedding.array();
        matches[0].flush({
          queryMap: {
            [queryKey]: {
              Response: 'Orange you glad I didn\'t say banana',
            },
          },
          embeddingMap: {
            [queryKey]: embeddingArrays[0],
          },
        });
        matches[1].flush({
          queryMap: {
          },
          embeddingMap: {
          },
        });
        matches[2].flush({
          queryMap: {
          },
          embeddingMap: {
          },
        });
        await loadPromise;
        const responsePromise = service.getResponse('Who\s there?', 'maid');
        const response = await responsePromise;
        expect(response).toBe('Orange you glad I didn\'t say banana');
        httpMock.verify();
      }));

    it('should return a query marked for any input', inject(
        [
          HttpTestingController,
          BotResponseService,
        ],
        async (httpMock: HttpTestingController, service: BotResponseService) => {
          const loadPromise = service.loadModels();
          const matches = httpMock.match(() => true);
          const queryKey = JSON.stringify([null]);
          matches[0].flush({
            queryMap: {
              [queryKey]: {
                Response: 'Anything goes!',
              },
            },
            embeddingMap: {
            },
          });
          matches[1].flush({
            queryMap: {
            },
            embeddingMap: {
            },
          });
          matches[2].flush({
            queryMap: {
            },
            embeddingMap: {
            },
          });
          await loadPromise;
          const responsePromise = service.getResponse('Who\s there?', 'maid');
          const response = await responsePromise;
          expect(response).toBe('Anything goes!');
          httpMock.verify();
        }));

    it('should check for state matching', inject(
        [
          HttpTestingController,
          BotResponseService,
        ],
        async (httpMock: HttpTestingController, service: BotResponseService) => {
          const loadPromise = service.loadModels();
          const matches = httpMock.match(() => true);
          const query = 'Can\'t you hear me knocking?';
          const state1 = 'some state';
          service.setState({
            maid: state1,
          });
          const response1 = 'On the window';
          const response2 = 'You\'re in a bad state';
          const queryKey1 = JSON.stringify([query, state1]);
          const queryKey2 = JSON.stringify([query]);
          const model = await use.load();
          const embedding = await model.embed([query]);
          const [embeddingArray] = await embedding.array();
          matches[0].flush({
            queryMap: {
              [queryKey1]: {
                Response: response1,
                State: state1,
              },
              [queryKey2]: {
                Response: response2,
              },
            },
            embeddingMap: {
              [queryKey1]: embeddingArray,
              [queryKey2]: embeddingArray,
            },
          });
          matches[1].flush({
            queryMap: {
            },
            embeddingMap: {
            },
          });
          matches[2].flush({
            queryMap: {
            },
            embeddingMap: {
            },
          });
          await loadPromise;
          const response = await service.getResponse('Can you hear me tapping?', 'maid');
          expect(response).toBe(response1);
          httpMock.verify();
        }));

    it('should change state on matched queries', inject(
      [
        HttpTestingController,
        BotResponseService,
      ],
      async (httpMock: HttpTestingController, service: BotResponseService) => {
        const loadPromise = service.loadModels();
        const matches = httpMock.match(() => true);
        const state = 'some state';
        const response = 'On the window';
        const queryKey = JSON.stringify([null]);
        matches[0].flush({
          queryMap: {
            [queryKey]: {
              Response: response,
              NewState: state,
            },
          },
          embeddingMap: {
          },
        });
        matches[1].flush({
          queryMap: {
          },
          embeddingMap: {
          },
        });
        matches[2].flush({
          queryMap: {
          },
          embeddingMap: {
          },
        });
        await loadPromise;
        await service.getResponse('Can you hear me tapping?', 'maid');
        expect(service.getState('maid')).toBe(state);
        httpMock.verify();
      }));
    });
});
Example #12
Source File: login.interceptor.spec.ts    From sba-angular with MIT License 4 votes vote down vote up
describe("login interceptor", () => {
  let interceptorInstance: HttpInterceptor | null;
  let httpClient: HttpClient;
  let httpMock: HttpTestingController;

  function getInterceptorInstance<T extends HttpInterceptor>(interceptors: HttpInterceptor[], type: any): HttpInterceptor | null {
    let searchedInterceptor: HttpInterceptor | null = null;
    interceptors.forEach((interceptor: HttpInterceptor) => {
      if (interceptor instanceof type) {
        searchedInterceptor = interceptor;
      }
    });
    return searchedInterceptor;
  }

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        HttpClientTestingModule,
        // ...
      ],
      providers: [
        {provide: START_CONFIG, useValue: {app: "testing_app"}},
        {provide: HTTP_REQUEST_INITIALIZERS, useValue: {}},
        {provide: LoginService, deps: [START_CONFIG], useClass: LoginService},
        {provide: AuthenticationService, deps: [START_CONFIG], useClass: AuthenticationService},
        {provide: HTTP_INTERCEPTORS, deps: [START_CONFIG, HTTP_REQUEST_INITIALIZERS, NotificationsService, LoginService, AuthenticationService], useClass: LoginInterceptor, multi: true}
      ]
    });

    // get interceptor instance
    interceptorInstance = getInterceptorInstance<LoginInterceptor>(TestBed.inject(HTTP_INTERCEPTORS), LoginInterceptor);

    httpClient = TestBed.inject(HttpClient);
    httpMock = TestBed.inject(HttpTestingController);
  });

  afterEach(() => {
    httpMock.verify();
  });

  it("should retrieve interceptors list", inject(
    [HTTP_INTERCEPTORS, START_CONFIG, LoginService, AuthenticationService],
    (interceptors: typeof HTTP_INTERCEPTORS) => {
      (interceptors as any).forEach((interceptor: HttpInterceptor) => {
        if (interceptor instanceof LoginInterceptor) {
          expect(interceptor).toBeDefined();
        }
      });
    }
  ));

  it("should instanciate interceptor", () => {
    expect(interceptorInstance).toBeDefined();
  })


  it('When 401, try to get Credentials or error is rethrow', () => {
    const login = TestBed.inject(LoginService);
    spyOn(login, "getCredentials").and.returnValue(Promise.resolve());
    // before refacto this method doesn't exists
    spyOn<any>(interceptorInstance, "handle401Error").and.callThrough();

    const message = '401 error';

    // Make an HTTP GET request
    httpClient.get("/data").subscribe(
      res => fail('should have failed with the 401 error'),
      (err: HttpErrorResponse) => {
        expect(err.error).toEqual(message, 'message');
      }
    );

    // The following `expectOne()` will match the request's URL.
    const req = httpMock.expectOne("/data");

    // Respond with mock error
    req.flush(message, {status: 401, statusText: 'Unauthorized'});

    expect(login.getCredentials).toHaveBeenCalledTimes(1);
    expect((interceptorInstance as LoginInterceptor)["handle401Error"]).toHaveBeenCalledTimes(1);
  });

  it('When an error occurs, error is rethrow', () => {
    const login = TestBed.inject(LoginService);
    spyOn(login, "getCredentials").and.returnValue(Promise.resolve());
    // before refacto this method doesn't exists
    spyOn<any>(interceptorInstance, "handle401Error").and.callThrough();

    const message = '403 Forbidden';

    // Make an HTTP GET request
    httpClient.get("/data").subscribe(
      res => fail('should have failed with the 403 error'),
      (err: HttpErrorResponse) => {
        expect(err.error).toEqual(message, 'message');
      }
    );

    // The following `expectOne()` will match the request's URL.
    const req = httpMock.expectOne("/data");

    // Respond with mock error
    req.flush(message, {status: 403, statusText: 'Forbidden'});

    expect(login.getCredentials).not.toHaveBeenCalled();
  });

  it("should intercept request", () => {
    httpClient.get("/data").subscribe(res => {
      expect(res).toEqual("ok");
    });

    const req = httpMock.expectOne("/data");
    req.flush("ok");

    expect(req.request.params.has("noAutoAuthentication")).toBeFalse();
    expect(req.request.params.has("noUserOverride")).toBeFalse();
    expect(req.request.params.has("noNotify")).toBeFalse();

    expect(req.request.headers.has("sinequa-force-camel-case")).toBeTrue();
  });

  it("should no intercept request with 'noIntercept' params", () => {
    // noIntercept
    const params = new HttpParams().set("noIntercept", "noIntercept")

    httpClient.get("/data", {params}).subscribe(res => {
      expect(res).toEqual("ok");
    });

    const req = httpMock.expectOne("/data?noIntercept=noIntercept");
    req.flush("ok");

  });

});
Example #13
Source File: expect-request.spec.ts    From s-libs with MIT License 4 votes vote down vote up
describe('expectRequest()', () => {
  let ctx: AngularContext;
  let http: HttpClient;
  beforeEach(() => {
    ctx = new AngularContext();
    http = ctx.inject(HttpClient);
  });

  function cleanUpPendingRequests(): void {
    ctx.inject(HttpTestingController).match(() => true);
  }

  it('allows optionally declaring the response body type', () => {
    ctx.run(() => {
      http.get('url 1').subscribe();
      http.get('url 2').subscribe();

      expectTypeOf(expectRequest<{ a: 1 }>('GET', 'url 1')).toEqualTypeOf<
        SlTestRequest<{ a: 1 }>
      >();
      expectTypeOf(expectRequest('GET', 'url 2')).toEqualTypeOf<
        SlTestRequest<HttpBody>
      >();
    });
  });

  it('returns a matching SlTestRequest', () => {
    ctx.run(() => {
      const method = 'GET';
      const url = 'a url';
      const request = new HttpRequest(method, url);
      http.request(request).subscribe();

      const req = expectRequest(method, url);

      expect(req.request).toBe(request);
    });
  });

  it('matches on method, url, params, headers and body', () => {
    ctx.run(async () => {
      const method = 'PUT';
      const url = 'correct_url';
      const body = 'correct_body';
      const options = {
        body,
        headers: { header: 'correct' },
        params: { param: 'correct' },
      };
      http.put(url, body, options).subscribe();

      expect(() => {
        expectRequest('DELETE', url, options);
      }).toThrowError();
      expect(() => {
        expectRequest(method, 'wrong', options);
      }).toThrowError();
      expect(() => {
        expectRequest(method, url, {
          ...options,
          params: { param: 'wrong' },
        });
      }).toThrowError();
      expect(() => {
        expectRequest(method, url, {
          ...options,
          headers: { header: 'wrong' },
        });
      }).toThrowError();
      expect(() => {
        expectRequest(method, url, { ...options, body: 'wrong' });
      }).toThrowError();
      expect(() => {
        expectRequest(method, url, options);
      }).not.toThrowError();
    });
  });

  it('has nice defaults', () => {
    ctx.run(async () => {
      const method = 'GET';
      const url = 'correct_url';
      http.get(url).subscribe();

      expect(() => {
        expectRequest(method, url, { params: { default: 'false' } });
      }).toThrowError();
      expect(() => {
        expectRequest(method, url, { headers: { default: 'false' } });
      }).toThrowError();
      expect(() => {
        expectRequest(method, url, { body: 'not_default' });
      }).toThrowError();
      expect(() => {
        expectRequest(method, url);
      }).not.toThrowError();
    });
  });

  it('throws a friendly message when there are no matches', () => {
    ctx.run(async () => {
      http.get('right').subscribe();
      http.get('right').subscribe();

      expect(() => {
        expectRequest('GET', 'wrong');
      }).toThrowError(
        `Expected 1 matching request, found 0. See details logged to the console.`,
      );
      expect(() => {
        expectRequest('GET', 'right');
      }).toThrowError(
        `Expected 1 matching request, found 2. See details logged to the console.`,
      );

      cleanUpPendingRequests();
    });
  });

  it('logs helpful details when there are no matches', () => {
    const log = spyOn(console, 'error');
    ctx.run(async () => {
      const request1 = new HttpRequest('GET', 'url 1');
      const request2 = new HttpRequest('DELETE', 'url 2');
      http.request(request1).subscribe();
      http.request(request2).subscribe();

      expect(() => {
        expectRequest('GET', 'bad url');
      }).toThrowError();
      expectSingleCallAndReset(
        log,
        'Expected 1 request to match:',
        { method: 'GET', url: 'bad url', params: {}, headers: {}, body: null },
        'Actual pending requests:',
        [request1, request2],
      );

      cleanUpPendingRequests();
    });
  });
});
Example #14
Source File: angular-context.spec.ts    From s-libs with MIT License 4 votes vote down vote up
describe('AngularContext', () => {
  class SnackBarContext extends AngularContext {
    constructor() {
      super({ imports: [MatSnackBarModule, NoopAnimationsModule] });
    }

    protected override cleanUp(): void {
      this.inject(OverlayContainer).ngOnDestroy();
      flush();
      super.cleanUp();
    }
  }

  describe('.getCurrent()', () => {
    it('returns the currently running angular context', () => {
      expect(AngularContext.getCurrent()).toBeUndefined();

      const ctx = new AngularContext();
      ctx.run(() => {
        expect(AngularContext.getCurrent()).toBe(ctx);
      });

      expect(AngularContext.getCurrent()).toBeUndefined();
    });
  });

  describe('.startTime', () => {
    it('controls the time at which the test starts', () => {
      const ctx = new AngularContext();
      ctx.startTime = new Date('2012-07-14T21:42:17.523Z');
      ctx.run(() => {
        expect(new Date()).toEqual(new Date('2012-07-14T21:42:17.523Z'));
      });
    });

    it('defaults to the current time', () => {
      const ctx = new AngularContext();
      const now = Date.now();
      ctx.run(() => {
        expect(Date.now()).toBeCloseTo(now, -1);
      });
    });
  });

  describe('constructor', () => {
    it('accepts module metadata to be bootstrapped', () => {
      const value = Symbol();
      const token = new InjectionToken<symbol>('tok');
      const ctx = new AngularContext({
        providers: [{ provide: token, useValue: value }],
      });
      ctx.run(() => {
        expect(ctx.inject(token)).toBe(value);
      });
    });

    it('sets up HttpClientTestingModule', () => {
      const ctx = new AngularContext();
      ctx.run(() => {
        expect(ctx.inject(HttpTestingController)).toBeDefined();
      });
    });

    it('sets up MockErrorHandler', () => {
      const ctx = new AngularContext();
      ctx.run(() => {
        expect(ctx.inject(ErrorHandler)).toEqual(jasmine.any(MockErrorHandler));
      });
    });

    it('gives a nice error message if trying to use 2 at the same time', () => {
      new AngularContext().run(async () => {
        expect(() => {
          // eslint-disable-next-line no-new -- nothing more is needed for this test
          new AngularContext();
        }).toThrowError(
          'There is already another AngularContext in use (or it was not cleaned up)',
        );
      });
    });
  });

  describe('.run()', () => {
    it('uses the fakeAsync zone', () => {
      const ctx = new AngularContext();
      ctx.run(() => {
        expect(tick).not.toThrow();
      });
    });

    it('can handle async tests that call tick', () => {
      let completed = false;
      const ctx = new AngularContext();
      ctx.run(async () => {
        await sleep(0);
        setTimeout(() => {
          completed = true;
        }, 500);
        ctx.tick(500);
      });
      expect(completed).toBeTrue();
    });

    it('does not swallow errors (production bug)', () => {
      expect(() => {
        new AngularContext().run(() => {
          throw new Error();
        });
      }).toThrowError();
    });
  });

  describe('.inject()', () => {
    it('fetches from the root injector', () => {
      const ctx = new AngularContext();
      ctx.run(() => {
        expect(ctx.inject(Injector)).toBe(TestBed.inject(Injector));
      });
    });
  });

  describe('.hasHarness()', () => {
    it('returns whether a match for the harness exists', () => {
      const ctx = new SnackBarContext();
      ctx.run(async () => {
        expect(await ctx.hasHarness(MatSnackBarHarness)).toBe(false);

        ctx.inject(MatSnackBar).open('hi');
        expect(await ctx.hasHarness(MatSnackBarHarness)).toBe(true);
      });
    });
  });

  describe('.getHarness()', () => {
    it('returns a harness', () => {
      const ctx = new SnackBarContext();
      ctx.run(async () => {
        ctx.inject(MatSnackBar).open('hi');
        const bar = await ctx.getHarness(MatSnackBarHarness);
        expect(await bar.getMessage()).toBe('hi');
      });
    });
  });

  describe('.getAllHarnesses()', () => {
    it('gets an array of harnesses', () => {
      const ctx = new SnackBarContext();
      ctx.run(async () => {
        let bars = await ctx.getAllHarnesses(MatSnackBarHarness);
        expect(bars.length).toBe(0);
        ctx.inject(MatSnackBar).open('hi');
        bars = await ctx.getAllHarnesses(MatSnackBarHarness);
        expect(bars.length).toBe(1);
        expect(await bars[0].getMessage()).toBe('hi');
      });
    });
  });

  describe('.tick()', () => {
    it('defaults to not advance time', () => {
      const ctx = new AngularContext();
      const start = ctx.startTime.getTime();
      ctx.run(() => {
        ctx.tick();
        expect(Date.now()).toBe(start);
      });
    });

    it('defaults to advancing in milliseconds', () => {
      const ctx = new AngularContext();
      const start = ctx.startTime.getTime();
      ctx.run(() => {
        ctx.tick(10);
        expect(Date.now()).toBe(start + 10);
      });
    });

    it('allows specifying the units to advance', () => {
      const ctx = new AngularContext();
      const start = ctx.startTime.getTime();
      ctx.run(() => {
        ctx.tick(10, 'sec');
        expect(Date.now()).toBe(start + 10000);
      });
    });

    it('runs change detection even if no tasks are queued', () => {
      let ranChangeDetection = false;

      @Component({ template: '' })
      class LocalComponent implements DoCheck {
        ngDoCheck(): void {
          ranChangeDetection = true;
        }
      }
      TestBed.overrideComponent(LocalComponent, {});

      const ctx = new AngularContext();
      ctx.run(() => {
        const resolver = ctx.inject(ComponentFactoryResolver);
        const factory = resolver.resolveComponentFactory(LocalComponent);
        const componentRef = factory.create(ctx.inject(Injector));
        ctx.inject(ApplicationRef).attachView(componentRef.hostView);

        expect(ranChangeDetection).toBe(false);
        ctx.tick();
        expect(ranChangeDetection).toBe(true);
      });
    });

    it('flushes micro tasks before running change detection', () => {
      let ranChangeDetection = false;
      let flushedMicroTasksBeforeChangeDetection = false;

      @Component({ template: '' })
      class LocalComponent implements DoCheck {
        ngDoCheck(): void {
          ranChangeDetection = true;
        }
      }
      TestBed.overrideComponent(LocalComponent, {});

      const ctx = new AngularContext();
      ctx.run(() => {
        const resolver = ctx.inject(ComponentFactoryResolver);
        const factory = resolver.resolveComponentFactory(LocalComponent);
        const componentRef = factory.create(ctx.inject(Injector));
        ctx.inject(ApplicationRef).attachView(componentRef.hostView);

        Promise.resolve().then(() => {
          flushedMicroTasksBeforeChangeDetection = !ranChangeDetection;
        });
        ctx.tick();
        expect(flushedMicroTasksBeforeChangeDetection).toBe(true);
      });
    });

    it('runs change detection after timeouts', () => {
      let ranTimeout = false;
      let ranChangeDetectionAfterTimeout = false;

      @Component({ template: '' })
      class LocalComponent implements DoCheck {
        ngDoCheck(): void {
          ranChangeDetectionAfterTimeout = ranTimeout;
        }
      }
      TestBed.overrideComponent(LocalComponent, {});

      const ctx = new AngularContext();
      ctx.run(() => {
        const resolver = ctx.inject(ComponentFactoryResolver);
        const factory = resolver.resolveComponentFactory(LocalComponent);
        const componentRef = factory.create(ctx.inject(Injector));
        ctx.inject(ApplicationRef).attachView(componentRef.hostView);

        setTimeout(() => {
          ranTimeout = true;
        });
        ctx.tick();
        expect(ranChangeDetectionAfterTimeout).toBe(true);
      });
    });

    it('advances `performance.now()`', () => {
      const ctx = new AngularContext();
      ctx.run(() => {
        const start = performance.now();
        ctx.tick(10);
        expect(performance.now()).toBe(start + 10);
      });
    });

    it('gives a nice error message when you try to use it outside `run()`', () => {
      const ctx = new AngularContext();
      expect(() => {
        ctx.tick();
      }).toThrowError(
        '.tick() only works inside the .run() callback (because it needs to be in a fakeAsync zone)',
      );
      ctx.run(noop);
    });
  });

  describe('.verifyPostTestConditions()', () => {
    it('errs if there are unexpected http requests', () => {
      const ctx = new AngularContext();
      expect(() => {
        ctx.run(() => {
          ctx.inject(HttpClient).get('an unexpected URL').subscribe();
        });
      }).toThrowError(
        'Expected no open requests, found 1: GET an unexpected URL',
      );
    });

    it('errs if there are unexpected errors', () => {
      @Component({ template: '<button (click)="throwError()"></button>' })
      class ThrowingComponent {
        throwError(): never {
          throw new Error();
        }
      }

      const ctx = new ComponentContext(ThrowingComponent);
      expect(() => {
        ctx.run(async () => {
          // TODO: make something like `ctx.getTestElement()`?
          const loader = FakeAsyncHarnessEnvironment.documentRootLoader(ctx);
          const button = await loader.locatorFor('button')();
          await button.click();
        });
      }).toThrowError('Expected no error(s), found 1');
    });
  });

  describe('.cleanUp()', () => {
    it('discards periodic tasks', () => {
      const ctx = new AngularContext();
      expect(() => {
        ctx.run(() => {
          setInterval(noop, 10);
        });
      })
        // No error: "1 periodic timer(s) still in the queue."
        .not.toThrowError();
    });

    it('flushes pending timeouts', () => {
      const ctx = new AngularContext();
      expect(() => {
        ctx.run(() => {
          setTimeout(noop, 1);
        });
      })
        // No error: "1 timer(s) still in the queue."
        .not.toThrowError();
    });
  });
});
Example #15
Source File: project-data-service.spec.ts    From barista with Apache License 2.0 4 votes vote down vote up
describe('Project Data Service', () => {
  let collectionService: ProjectService;
  let dataService: ProjectDataService;
  let backend: HttpTestingController;
  let service: ProjectApiService;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        HttpClientTestingModule,
        StoreModule.forRoot({}),
        EffectsModule.forRoot([]),
        EntityDataModule.forRoot(entityConfig),
        EntityStoreModule,
        ApiModule,
      ],
      providers: [
        Store,
        {
          provide: HttpUrlGenerator,
          useClass: DefaultHttpUrlGenerator,
        },
        {
          provide: Logger,
          useClass: DefaultLogger,
        },
        ProjectDataService,
        ProjectService,
      ],
    }).compileComponents();
  }));

  beforeEach(() => {
    collectionService = TestBed.get(ProjectService);
    dataService = TestBed.get(ProjectDataService);
    service = TestBed.get(ProjectApiService);
    backend = TestBed.get(HttpTestingController);
  });

  it('should create', () => {
    expect(dataService).toBeTruthy();
  });

  it('should create an entity', done => {
    const expected = {
      id: 1,
      name: 'Test Project',
    } as Project;

    const project = { name: expected.name } as Project;
    dataService
      .add(project)
      .pipe(take(1))
      .subscribe(actual => {
        expect(actual).toEqual(expected);
        done();
      });

    const requestWrapper = backend.expectOne(`${service.configuration.basePath}/project`);
    requestWrapper.flush(expected);
  });

  it('should retrieve a created entity', done => {
    const expected = {
      id: 1,
      name: 'Test Project',
    } as Project;

    const project = { name: expected.name } as Project;

    collectionService
      .add(project)
      .pipe(take(1))
      .subscribe(result => {
        expect(result).toEqual(expected);
      });

    const subscription = collectionService.entities$.pipe().subscribe(actual => {
      if (actual.length > 0) {
        expect(actual[0]).toEqual(expected);
        subscription.unsubscribe();
        done();
      }
    });

    const requestWrapper = backend.expectOne(`${service.configuration.basePath}/project`);
    requestWrapper.flush(expected);
  });
});
Example #16
Source File: photo.service.spec.ts    From dating-client with MIT License 4 votes vote down vote up
describe('PhotoService', () => {
  let photoService: PhotoService;
  let httpMock: HttpTestingController;
  const apiUrl = '/api';

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [ HttpClientTestingModule ],
      providers: [
        { provide: API_URL, useValue: apiUrl },
        PhotoService
      ]
    });

    // Inject the service that we want to test
    photoService = TestBed.inject(PhotoService);
    // Inject the HttpTestingController in order to mock api responses
    httpMock = TestBed.inject(HttpTestingController);
  });

  // After every test, assert that there are no more pending requests.
  afterEach(() => httpMock.verify());

  it('should be created', () => {
    expect(photoService).toBeTruthy();
  });

  describe('#uploadPhoto', () => {
    const testPhoto: Photo = {
      id: 1,
      url: 'http://test.com',
      description: 'test',
      addedAt: new Date(),
      isMain: true
    };
    const userId = 1;
    const path = `${ apiUrl }/users/${ userId }/photos`;

    it('should return a photo, empty object or null', (done) => {
      photoService.uploadPhoto(testPhoto, userId).subscribe(res => {
        expect(res).toEqual(testPhoto);
      });

      photoService.uploadPhoto({}, userId).subscribe(res => {
        expect(res).toEqual({});
        expect(res.description).toBe(undefined);
      });

      photoService.uploadPhoto(null, userId).subscribe(res => {
        expect(res).toEqual(null);
        done();
      });

      // get all pending requests that match the given URL
      const requests = httpMock.match(path);

      // Assert that the first request is a POST.
      expect(requests[0].request.method).toEqual('POST');

      // Respond with mock data, causing Observable to resolve.
      // Subscribe callback asserts that correct data was returned.
      requests[0].flush(testPhoto);
      requests[1].flush({});
      requests[2].flush(null);
    });

    it('should return an error message', () => {
      const errorMessage = 'Error!!!';

      photoService.uploadPhoto({}, userId).subscribe(
        res => {
          expect(res).toEqual({});
        },
        (error: HttpErrorResponse) => {
          expect(error.status).toEqual(404);
          expect(error.statusText).toEqual('Not Found');
          expect(error.error).toEqual(errorMessage);
        }
      );

      const req = httpMock.expectOne(path);

      req.flush(errorMessage, { status: 404, statusText: 'Not Found' });
    });
  });

  describe('#setMainPhoto', () => {
    const userId = 1;
    const photoId = 1;

    const path = `${ apiUrl }/users/${ userId }/photos/${ photoId }/setMain`;

    it('should return empty object', () => {
      photoService.setMainPhoto(userId, photoId).subscribe(res => {
        expect(res).toEqual({});
      });

      // The following `expectOne()` will match the request's URL.
      // If no requests or multiple requests matched that URL `expectOne()` would throw.
      const req = httpMock.expectOne(path);

      expect(req.request.method).toEqual('POST');

      req.flush({});
    });

  });

  describe('#deletePhoto', () => {
    const path = `${ apiUrl }/users/${ 1 }/photos/${ 1 }`;

    it('should return empty object (void)', () => {
      photoService.deletePhoto(1, 1).subscribe(res =>
        expect(res).toEqual({})
      );
      const req = httpMock.expectOne(path);
      expect(req.request.method).toEqual('DELETE');
      req.flush({});
    });
  });

});
Example #17
Source File: member.service.spec.ts    From dating-client with MIT License 4 votes vote down vote up
describe('MemberService', () => {
  let memberService: MemberService;
  let httpMock: HttpTestingController;
  const apiUrl = '/api';

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [ HttpClientTestingModule ],
      providers: [
        { provide: API_URL, useValue: apiUrl },
        MemberService
      ]
    });

    memberService = TestBed.inject(MemberService);
    httpMock = TestBed.inject(HttpTestingController);
  });

  afterEach(() => {
    httpMock.verify();
  });

  it('should be created', () => {
    expect(memberService).toBeTruthy();
  });

  describe('createParamsFromFilter method', () => {
    it('should return only valid http params', () => {
      const filters: Partial<IQueryParams & MembersFilter> = {
        gender: '',
        lastActive: undefined,
        pageNumber: '',
        minAge: '22',
        maxAge: undefined,
        pageSize: '2'
      };
      const params = memberService.createParamsFromFilter(filters);
      expect(params.toString()).toBe('MinAge=22&PageSize=2');
    });
  });

  describe('getMembers method', () => {
    const filters: Partial<IQueryParams & MembersFilter> = {
      gender: '',
      lastActive: '',
      maxAge: '99',
      minAge: '18',
      pageNumber: undefined,
      pageSize: '2'
    };
    const pagination: Pagination = {
      currentPage: 1,
      itemsPerPage: 2,
      totalItems: 10,
      totalPages: 5
    };
    const membersList: User[] = [
      { id: 1, username: 'test1' },
      { id: 2, username: 'test2' }
    ];
    const path = `${apiUrl}/users`;

    it('should return a paginated result of users', () => {
      memberService.getMembers(filters).subscribe(res => {
        expect(res).toEqual({ pagination, result: membersList });
        expect(res.pagination).toBe(pagination);
        expect(res.result).toBe(membersList);
      });

      memberService.getMembers(filters).subscribe(res => {
        expect(res).toEqual({});
        expect(res.pagination).toEqual(pagination);
      });

      const params = memberService.createParamsFromFilter(filters);

      const pathWithParams = path + '?' + params.toString();

      const requests = httpMock.match(pathWithParams);
      expect(requests[ 0 ].request.urlWithParams).toBe(pathWithParams);
      expect(requests[ 0 ]?.request?.method).toEqual('GET');

      const headers = { Pagination: JSON.stringify(pagination) };

      requests[ 0 ].flush(membersList, { headers });
      requests[ 1 ].flush({}, { headers });
    });

    it('should return an error message', () => {
      const errorMessage = 'Error!!!';

      memberService.getMembers({}).subscribe(
        () => {
        },
        (error: HttpErrorResponse) => {
          expect(error.status).toEqual(404);
          expect(error.statusText).toEqual('Not Found');
          expect(error.error).toEqual(errorMessage);
        }
      );

      const req = httpMock.expectOne(path);

      req.flush(errorMessage, { status: 404, statusText: 'Not Found' });
    });

  });

  describe('getMemberDetails method', () => {
    const testUser: User = { id: 1, username: 'test' };
    const path = `${apiUrl}/users/${1}`;

    it('should return a User or empty object', () => {
      memberService.getMemberDetails(1).subscribe(res => {
        expect(res).toEqual(testUser);
      });

      memberService.getMemberDetails(1).subscribe(res => {
        expect(res).toEqual({});
        expect(res.id).toBe(undefined);
      });

      const requests = httpMock.match(path);

      expect(requests[ 0 ].request.method).toEqual('GET');

      requests[ 0 ].flush(testUser);
      requests[ 1 ].flush({});
    });

    it('should return an error message', () => {
      const errorMessage = 'Error!!!';

      memberService.getMemberDetails(1).subscribe(
        () => {
        },
        (error: HttpErrorResponse) => {
          expect(error.status).toEqual(404);
          expect(error.statusText).toEqual('Not Found');
          expect(error.error).toEqual(errorMessage);
        }
      );

      const req = httpMock.expectOne(path);

      req.flush(errorMessage, { status: 404, statusText: 'Not Found' });
    });

  });

  describe('editMember method', () => {
    const testUser: User = { id: 1, username: 'test' };
    const path = `${apiUrl}/users/${testUser.username}`;

    it('should return a User', () => {
      memberService.editMember(testUser).subscribe(res => {
        expect(res).toEqual(testUser);
        expect(res.id).toEqual(testUser.id);
      });

      const req = httpMock.expectOne(path);
      expect(req.request.method).toEqual('PUT');
      req.flush(testUser);
    });

    it('should return an error message', () => {
      const errorMessage = 'Error!!!';
      const testUser: User = { id: 1, username: 'test' };
      memberService.editMember(testUser).subscribe(
        () => { },
        (error: HttpErrorResponse) => {
          expect(error.status).toEqual(404);
          expect(error.statusText).toEqual('Not Found');
          expect(error.error).toEqual(errorMessage);
        }
      );
      const req = httpMock.expectOne(path);
      req.flush(errorMessage, { status: 404, statusText: 'Not Found' });
    });

  });

});
Example #18
Source File: error.interceptor.spec.ts    From dating-client with MIT License 4 votes vote down vote up
describe('Error Interceptor', () => {
  let httpClient: HttpClient;
  let httpMock: HttpTestingController;
  const url = '/api';

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [ HttpClientTestingModule ],
      // providers: [ ErrorInterceptorProvider ]
    });

    httpClient = TestBed.inject(HttpClient);
    httpMock = TestBed.inject(HttpTestingController);
  });

  // Assert that there are no outstanding requests.
  afterEach(() => httpMock.verify());

  it('should not throw error if no error is emitted', () => {
    httpClient.get(url).subscribe({
      next: res => expect(res).toBe(1),
      error: err => expect(err).toBeFalsy()
    });

    const req = httpMock.expectOne(url);
    expect(req.request.method).toEqual('GET');

    req.flush(1);
  });

  /** Any error returned on the Observable response stream
   * will be wrapped in an HttpErrorResponse to provide additional
   * context about the state of the HTTP layer when the error occurred.
   * The error property will contain either a wrapped Error object
   * or the error response returned from the server.
   */
  // describe('with error that is instanceof HttpErrorResponse', () => {
  //
  //   describe('with error status: 0', () => {
  //     it('and statusText: \'Unknown Error\' should throw \'Server is not responding!\'', done => {
  //       httpClient.get('/api').subscribe(x => {
  //         },
  //         err => {
  //           expect(err).toBe('Server is not responding!');
  //           done();
  //         });
  //
  //       const req = httpMock.expectOne('/api');
  //
  //       req.error(new ErrorEvent('HttpErrorResponse'), { status: 0, statusText: 'Unknown Error' });
  //     });
  //
  //     it('should dispatch logout action and throw statusText of the error', done => {
  //       httpClient.get('/api').subscribe(x => {
  //         },
  //         err => {
  //           expect(err).toBe('ErrorMessage');
  //           done();
  //         });
  //
  //       const req = httpMock.expectOne('/api');
  //
  //       req.flush('Error!!!', { status: 0, statusText: 'ErrorMessage' });
  //
  //       // const expected = cold('a', { a: logout() });
  //       // expect(store.scannedActions$).toBeObservable(expected);
  //     });
  //   });
  //
  //   describe('with error status: 401', () => {
  //     it('and statusText: \'Unauthorized\' should throw \'You are not authorized!\' and dispatch logout action', done => {
  //       httpClient.get('/api').subscribe(x => {
  //         },
  //         err => {
  //           expect(err).toBe('You are not authorized!');
  //           done();
  //         });
  //
  //       const req = httpMock.expectOne('/api');
  //
  //       req.flush('Error!!!', { status: 401, statusText: 'Unauthorized' });
  //
  //       // const expected = cold('a', { a: logout() });
  //       // expect(store.scannedActions$).toBeObservable(expected);
  //     });
  //
  //     it('should throw statusText of the error', done => {
  //       httpClient.get('/api').subscribe(
  //         x => {
  //         },
  //         err => {
  //           expect(err).toBe('ErrorMessage');
  //           done();
  //         }
  //       );
  //
  //       const req = httpMock.expectOne('/api');
  //
  //       req.flush('Error!!!', { status: 401, statusText: 'ErrorMessage' });
  //     });
  //   });
  //
  //   it('with error status: 500, should throw body of the error', done => {
  //     httpClient.get('/api').subscribe(x => {
  //       },
  //       err => {
  //         expect(err).toBe('Internal Server Error.');
  //         done();
  //       });
  //
  //     const req = httpMock.expectOne('/api');
  //
  //     req.flush('Internal Server Error.', { status: 500, statusText: 'test' });
  //   });
  //
  //   it('and has \'Application-Error\' header should throw header error', done => {
  //     httpClient.get('/api').subscribe(
  //       x => {
  //       },
  //       err => {
  //         expect(err).toBe('ErrorMessage!');
  //         done();
  //       }
  //     );
  //
  //     const req = httpMock.expectOne('/api');
  //
  //     req.flush('Error!!!', {
  //       status: 405,
  //       statusText: 'ErrorStatusText',
  //       headers: { 'Application-Error': 'ErrorMessage!' }
  //     });
  //   });
  //
  //   it('with error status: 400, should throw model state error', done => {
  //     const serverError = {
  //       errors: {
  //         username: [ 'Username cannot be longer than 20 characters.' ],
  //         password: [ 'Password cannot be shorter than 8 characters.' ]
  //       }
  //     };
  //     const { errors } = serverError;
  //
  //     httpClient.get('/api').subscribe(x => {
  //       },
  //       err => {
  //         let modelStateErrors = '';
  //         if (typeof errors === 'object') {
  //           for (const key in errors) {
  //             // @ts-ignore
  //             modelStateErrors += errors[key] + '\n';
  //           }
  //         }
  //         expect(err).toBe(modelStateErrors);
  //         done();
  //       });
  //
  //     const req = httpMock.expectOne('/api');
  //
  //     req.flush(serverError, {
  //       status: 400,
  //       statusText: 'ErrorStatusText',
  //     });
  //   });
  //
  // });

});
Example #19
Source File: auth.interceptor.spec.ts    From auth0-angular with MIT License 4 votes vote down vote up
// NOTE: Read Async testing: https://github.com/angular/angular/issues/25733#issuecomment-636154553

describe('The Auth HTTP Interceptor', () => {
  let httpClient: HttpClient;
  let httpTestingController: HttpTestingController;
  let auth0Client: Auth0Client;
  let req: TestRequest;
  let authState: AuthState;
  const testData: Data = { message: 'Hello, world' };

  const assertAuthorizedApiCallTo = (
    url: string,
    done: () => void,
    method = 'get'
  ) => {
    httpClient.request(method, url).subscribe(done);
    flush();
    req = httpTestingController.expectOne(url);

    expect(req.request.headers.get('Authorization')).toBe(
      'Bearer access-token'
    );
  };

  const assertPassThruApiCallTo = (url: string, done: () => void) => {
    httpClient.get<Data>(url).subscribe(done);
    flush();
    req = httpTestingController.expectOne(url);
    expect(req.request.headers.get('Authorization')).toBeFalsy();
  };

  let config: Partial<AuthConfig>;

  beforeEach(() => {
    req = undefined as any;

    auth0Client = new Auth0Client({
      domain: '',
      client_id: '',
    });

    spyOn(auth0Client, 'getTokenSilently').and.resolveTo('access-token');

    config = {
      httpInterceptor: {
        allowedList: [
          '',
          'https://my-api.com/api/photos',
          'https://my-api.com/api/people*',
          'https://my-api.com/orders',
          {
            uri: 'https://my-api.com/api/orders',
            allowAnonymous: true,
          },
          {
            uri: 'https://my-api.com/api/addresses',
            tokenOptions: {
              audience: 'audience',
              scope: 'scope',
            },
          },
          {
            uri: 'https://my-api.com/api/calendar*',
          },
          {
            uri: 'https://my-api.com/api/register',
            httpMethod: HttpMethod.Post,
          },
          {
            uriMatcher: (uri) => uri.indexOf('/api/contact') !== -1,
            httpMethod: HttpMethod.Post,
            tokenOptions: {
              audience: 'audience',
              scope: 'scope',
            },
          },
        ],
      },
    };

    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [
        {
          provide: HTTP_INTERCEPTORS,
          useClass: AuthHttpInterceptor,
          multi: true,
        },
        {
          provide: Auth0ClientService,
          useValue: auth0Client,
        },
        {
          provide: AuthClientConfig,
          useValue: { get: () => config },
        },
      ],
    });

    httpClient = TestBed.inject(HttpClient);
    httpTestingController = TestBed.inject(HttpTestingController);
    authState = TestBed.inject(AuthState);

    spyOn(authState, 'setError').and.callThrough();
  });

  afterEach(() => {
    httpTestingController.verify();
    if (req) {
      req.flush(testData);
    }
  });

  describe('When no httpInterceptor is configured', () => {
    it('pass through and do not have access tokens attached', fakeAsync((
      done: () => void
    ) => {
      config.httpInterceptor = (null as unknown) as HttpInterceptorConfig;
      assertPassThruApiCallTo('https://my-api.com/api/public', done);
    }));
  });

  describe('Requests that do not require authentication', () => {
    it('pass through and do not have access tokens attached', fakeAsync((
      done: () => void
    ) => {
      assertPassThruApiCallTo('https://my-api.com/api/public', done);
    }));
  });

  describe('Requests that are configured using a primitive', () => {
    it('attach the access token when the configuration uri is a string', fakeAsync((
      done: () => void
    ) => {
      // Testing /api/photos (exact match)
      assertAuthorizedApiCallTo('https://my-api.com/api/photos', done);
    }));

    it('attach the access token when the configuration uri is a string with a wildcard', fakeAsync((
      done: () => void
    ) => {
      // Testing /api/people* (wildcard match)
      assertAuthorizedApiCallTo('https://my-api.com/api/people/profile', done);
    }));

    it('matches a full url to an API', fakeAsync((done: () => void) => {
      // Testing 'https://my-api.com/orders' (exact)
      assertAuthorizedApiCallTo('https://my-api.com/orders', done);
    }));

    it('matches a URL that contains a query string', fakeAsync((
      done: () => void
    ) => {
      assertAuthorizedApiCallTo(
        'https://my-api.com/api/people?name=test',
        done
      );
    }));

    it('matches a URL that contains a hash fragment', fakeAsync((
      done: () => void
    ) => {
      assertAuthorizedApiCallTo(
        'https://my-api.com/api/people#hash-fragment',
        done
      );
    }));
  });

  describe('Requests that are configured using a complex object', () => {
    it('attach the access token when the uri is configured using a string', fakeAsync((
      done: () => void
    ) => {
      // Testing { uri: /api/orders } (exact match)
      assertAuthorizedApiCallTo('https://my-api.com/api/orders', done);
    }));

    it('pass through the route options to getTokenSilently, without additional properties', fakeAsync((
      done: () => void
    ) => {
      // Testing { uri: /api/addresses } (exact match)
      assertAuthorizedApiCallTo('https://my-api.com/api/addresses', done);

      expect(auth0Client.getTokenSilently).toHaveBeenCalledWith({
        audience: 'audience',
        scope: 'scope',
      });
    }));

    it('attach the access token when the configuration uri is a string with a wildcard', fakeAsync((
      done: () => void
    ) => {
      // Testing { uri: /api/calendar* } (wildcard match)
      assertAuthorizedApiCallTo('https://my-api.com/api/calendar/events', done);
    }));

    it('attaches the access token when the HTTP method matches', fakeAsync((
      done: () => void
    ) => {
      // Testing { uri: /api/register } (wildcard match)
      assertAuthorizedApiCallTo(
        'https://my-api.com/api/register',
        done,
        'post'
      );
    }));

    it('does not attach the access token if the HTTP method does not match', fakeAsync((
      done: () => void
    ) => {
      assertPassThruApiCallTo('https://my-api.com/api/public', done);
    }));

    it('does not execute HTTP call when not able to retrieve a token', fakeAsync((
      done: () => void
    ) => {
      (auth0Client.getTokenSilently as jasmine.Spy).and.returnValue(
        throwError({ error: 'login_required' })
      );

      httpClient.request('get', 'https://my-api.com/api/calendar').subscribe({
        error: (err) => expect(err).toEqual({ error: 'login_required' }),
      });

      httpTestingController.expectNone('https://my-api.com/api/calendar');
      flush();
    }));

    it('does execute HTTP call when not able to retrieve a token but allowAnonymous is set to true', fakeAsync((
      done: () => void
    ) => {
      (auth0Client.getTokenSilently as jasmine.Spy).and.returnValue(
        throwError({ error: 'login_required' })
      );

      assertPassThruApiCallTo('https://my-api.com/api/orders', done);
    }));

    it('emit error when not able to retrieve a token but allowAnonymous is set to false', fakeAsync((
      done: () => void
    ) => {
      (auth0Client.getTokenSilently as jasmine.Spy).and.callFake(() => {
        return Promise.reject({ error: 'login_required' });
      });

      httpClient.request('get', 'https://my-api.com/api/calendar').subscribe({
        error: (err) => expect(err).toEqual({ error: 'login_required' }),
      });

      httpTestingController.expectNone('https://my-api.com/api/calendar');
      flush();

      expect(authState.setError).toHaveBeenCalled();
    }));

    it('does not emit error when not able to retrieve a token but allowAnonymous is set to true', fakeAsync(() => {
      (auth0Client.getTokenSilently as jasmine.Spy).and.callFake(() => {
        return Promise.reject({ error: 'login_required' });
      });

      assertPassThruApiCallTo('https://my-api.com/api/orders', () => {
        expect(authState.setError).not.toHaveBeenCalled();
      });
    }));
  });

  describe('Requests that are configured using an uri matcher', () => {
    it('attach the access token when the matcher returns true', fakeAsync((
      done: () => void
    ) => {
      // Testing { uriMatcher: (uri) => uri.indexOf('/api/contact') !== -1 }
      assertAuthorizedApiCallTo('https://my-api.com/api/contact', done, 'post');
    }));

    it('pass through the route options to getTokenSilently, without additional properties', fakeAsync((
      done: () => void
    ) => {
      // Testing { uriMatcher: (uri) => uri.indexOf('/api/contact') !== -1 }
      assertAuthorizedApiCallTo('https://my-api.com/api/contact', done, 'post');

      expect(auth0Client.getTokenSilently).toHaveBeenCalledWith({
        audience: 'audience',
        scope: 'scope',
      });
    }));

    it('does not attach the access token when the HTTP method does not match', fakeAsync((
      done: () => void
    ) => {
      // Testing { uriMatcher: (uri) => uri.indexOf('/api/contact') !== -1 }
      assertAuthorizedApiCallTo('https://my-api.com/api/contact', done, 'post');
      assertPassThruApiCallTo('https://my-api.com/api/contact', done);
    }));
  });
});
Example #20
Source File: todos.api.spec.ts    From angular-padroes-e-boas-praticas with MIT License 4 votes vote down vote up
describe('TodosApi', () => {

  let service: TodosApi;
  let httpTestingController: HttpTestingController;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [TodosApi],
      imports: [HttpClientTestingModule]
    });
  });

  beforeEach(() => {
      service = TestBed.inject(TodosApi);
      httpTestingController = TestBed.inject(HttpTestingController);
  });

  afterEach(() => {
      httpTestingController.verify();
  });


  it('should be created', () => {
      expect(service).toBeTruthy();
  });

  describe('#list', () => {
    it('returned Observable should match the right data', () => {
        const searchQuery = 'search';
        service.list(searchQuery)
          .subscribe(todos => {
            expect(todos[0].title).toEqual(mockAllTodos[0].title);
            expect(todos[1].title).toEqual(mockAllTodos[1].title);
          });

        const req = httpTestingController
          .expectOne(`${environment.apiBaseUrl}/todos?search=${searchQuery}`);
        expect(req.request.method).toEqual('GET');
        req.flush(mockAllTodos);
    });
  });

  describe('#create', async () => {
    it('returned Observable should match the right data', () => {
      service.create(mockTodo)
          .subscribe(todo => {
              expect(todo.title).toEqual(mockTodo.title);
          });

      const req = httpTestingController.expectOne(`${environment.apiBaseUrl}/todos`);
      expect(req.request.method).toEqual('POST');
      req.flush(mockTodo);
    });
  });

  describe('#remove', async () => {
    it('returned Observable should match the right data', () => {
      service.remove(mockTodo.id)
          .subscribe(todo => {
            expect(todo).toEqual(mockTodo);
          });

      const req = httpTestingController.expectOne(`${environment.apiBaseUrl}/todos/${mockTodo.id}`);
      expect(req.request.method).toEqual('DELETE');
      req.flush(mockTodo);
    });
  });

  describe('#toggleCompleted', async () => {
    it('returned Observable should match the right data', () => {
      service.toggleCompleted(mockTodo.id, true)
          .subscribe(todo => {
              expect(todo.id).toEqual(mockTodo.id);
              expect(todo.isCompleted).toEqual(true);
          });

      const req = httpTestingController.expectOne(`${environment.apiBaseUrl}/todos/${mockTodo.id}`);
      expect(req.request.method).toEqual('PUT');
      req.flush({ ...mockTodo, isCompleted: true});
    });
  });
});