diff --git a/src/app/shared/log-in/log-in.component.spec.ts b/src/app/shared/log-in/log-in.component.spec.ts index 6992afa5ec..adb7187757 100644 --- a/src/app/shared/log-in/log-in.component.spec.ts +++ b/src/app/shared/log-in/log-in.component.spec.ts @@ -16,6 +16,12 @@ import { AppState } from '../../app.reducer'; import {AppRoutingModule} from '../../app-routing.module'; import {PageNotFoundComponent} from '../../pagenotfound/pagenotfound.component'; import {APP_BASE_HREF} from '@angular/common'; +import {HostWindowService} from '../host-window.service'; +import {HostWindowServiceStub} from '../testing/host-window-service-stub'; +import {RouterStub} from '../testing/router-stub'; +import {NavigationEnd, Router} from '@angular/router'; +import {Observable, of as observableOf} from 'rxjs'; +import {RouterEventsStub} from '../testing/router-events-stub'; describe('LogInComponent', () => { @@ -50,7 +56,9 @@ describe('LogInComponent', () => { ], providers: [ {provide: AuthService, useClass: AuthServiceStub}, - {provide: APP_BASE_HREF, useValue: '/'} + {provide: APP_BASE_HREF, useValue: '/'}, + {provide: Router, useClass: RouterStub}, + {provide: HostWindowService, useValue: new HostWindowServiceStub(900) } ], schemas: [ CUSTOM_ELEMENTS_SCHEMA @@ -118,11 +126,13 @@ describe('LogInComponent', () => { expect(authService.setRedirectUrl).toHaveBeenCalled(); }); - it('should not set the redirect url because one already exists', () => { + it('should not set the redirect url to /login', () => { fixture.detectChanges(); + const router: Router = TestBed.get(Router); + router.navigateByUrl('/login') + const authService: AuthService = TestBed.get(AuthService); - authService.setRedirectUrl('/submit') // set FormControl values component.form.controls.email.setValue('user'); @@ -135,6 +145,101 @@ describe('LogInComponent', () => { expect(authService.setRedirectUrl).not.toHaveBeenCalled(); }); + it('should not set the redirect url on init', () => { + + const authService: AuthService = TestBed.get(AuthService); + spyOn(authService, 'setRedirectUrl'); + + fixture.detectChanges(); + expect(authService.setRedirectUrl).not.toHaveBeenCalledWith(); + + }); + +}); + +describe('LogInComponent on small screen', () => { + + let component: LogInComponent; + let fixture: ComponentFixture; + let page: Page; + let user: EPerson; + + const navEvents = observableOf( + new NavigationEnd(0, 'http://localhost:3000/home', 'http://localhost:3000/home'), + new NavigationEnd(1, 'http://localhost:3000/login', 'http://localhost:3000/login') + ); + + const authState = { + authenticated: false, + loaded: false, + loading: false, + }; + + beforeEach(() => { + user = EPersonMock; + }); + + beforeEach(async(() => { + // refine the test module by declaring the test component + TestBed.configureTestingModule({ + imports: [ + FormsModule, + ReactiveFormsModule, + StoreModule.forRoot(authReducer), + AppRoutingModule, + TranslateModule.forRoot() + ], + declarations: [ + LogInComponent, + PageNotFoundComponent + ], + providers: [ + {provide: AuthService, useClass: AuthServiceStub}, + {provide: APP_BASE_HREF, useValue: '/'}, + {provide: Router, useValue: new RouterEventsStub(navEvents)}, + {provide: HostWindowService, useValue: new HostWindowServiceStub(300) } + ], + schemas: [ + CUSTOM_ELEMENTS_SCHEMA + ] + }) + .compileComponents(); + + })); + + beforeEach(inject([Store], (store: Store) => { + store + .subscribe((state) => { + (state as any).core = Object.create({}); + (state as any).core.auth = authState; + }); + + // create component and test fixture + fixture = TestBed.createComponent(LogInComponent); + + // get test component from the fixture + component = fixture.componentInstance; + + // create page + page = new Page(component, fixture); + + // verify the fixture is stable (no pending tasks) + fixture.whenStable().then(() => { + page.addPageElements(); + }); + + })); + + it('should set the redirect url on init', () => { + + const authService: AuthService = TestBed.get(AuthService); + spyOn(authService, 'setRedirectUrl'); + + fixture.detectChanges(); + expect(authService.setRedirectUrl).toHaveBeenCalledWith('http://localhost:3000/home'); + + }); + }); /** diff --git a/src/app/shared/log-in/log-in.component.ts b/src/app/shared/log-in/log-in.component.ts index 13fa73bc4e..0821ff1678 100644 --- a/src/app/shared/log-in/log-in.component.ts +++ b/src/app/shared/log-in/log-in.component.ts @@ -1,4 +1,4 @@ -import {filter, map, take, takeWhile, tap} from 'rxjs/operators'; +import {filter, map, pairwise, take, takeWhile, tap} from 'rxjs/operators'; import { Component, OnDestroy, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; @@ -19,8 +19,9 @@ import { CoreState } from '../../core/core.reducers'; import {isEmpty, isNotEmpty} from '../empty.util'; import { fadeOut } from '../animations/fade'; -import { AuthService } from '../../core/auth/auth.service'; -import {Router} from '@angular/router'; +import {AuthService, LOGIN_ROUTE} from '../../core/auth/auth.service'; +import {NavigationEnd, Router, RoutesRecognized} from '@angular/router'; +import {HostWindowService} from '../host-window.service'; /** * /users/sign-in @@ -82,17 +83,21 @@ export class LogInComponent implements OnDestroy, OnInit { */ private alive = true; + private redirectUrl = LOGIN_ROUTE; + /** * @constructor * @param {AuthService} authService * @param {FormBuilder} formBuilder * @param {Router} router + * @param {HostWindowService} windowService * @param {Store} store */ constructor( private authService: AuthService, private formBuilder: FormBuilder, private router: Router, + private windowService: HostWindowService, private store: Store ) { } @@ -101,10 +106,22 @@ export class LogInComponent implements OnDestroy, OnInit { * Lifecycle hook that is called after data-bound properties of a directive are initialized. * @method ngOnInit */ - public ngOnInit() { - // set isAuthenticated + public ngOnInit() { // set isAuthenticated this.isAuthenticated = this.store.pipe(select(isAuthenticated)); + // for mobile login, set the redirect url to the previous route + this.windowService.isXs().pipe(take(1)) + .subscribe((isMobile) => { + if (isMobile) { + this.router.events.pipe( + filter((e: any) => e instanceof NavigationEnd), + pairwise() + ).subscribe((e: any) => { + this.setRedirectUrl(e[0].urlAfterRedirects); + }); + } + }); + // set formGroup this.form = this.formBuilder.group({ email: ['', Validators.required], @@ -185,17 +202,21 @@ export class LogInComponent implements OnDestroy, OnInit { email.trim(); password.trim(); - this.authService.getRedirectUrl().pipe( - take(1)). - subscribe((r) => { - // Set the redirect url if none exists. - if (isEmpty(r)) { - this.authService.setRedirectUrl(this.router.url) - } - // dispatch AuthenticationAction - this.store.dispatch(new AuthenticateAction(email, password)); - // clear form - this.form.reset(); - }); + this.setRedirectUrl(this.router.url); + // dispatch AuthenticationAction + this.store.dispatch(new AuthenticateAction(email, password)); + // clear form + this.form.reset(); + + } + + /** + * Sets the redirect url if not LOGIN_ROUTE + * @param url + */ + private setRedirectUrl(url: string) { + if (url !== this.redirectUrl) { + this.authService.setRedirectUrl(url) + } } } diff --git a/src/app/shared/testing/router-events-stub.ts b/src/app/shared/testing/router-events-stub.ts new file mode 100644 index 0000000000..313f6a2b4e --- /dev/null +++ b/src/app/shared/testing/router-events-stub.ts @@ -0,0 +1,24 @@ +import {Observable, of as observableOf} from 'rxjs'; +export class RouterEventsStub { + url: string; + routeReuseStrategy = {shouldReuseRoute: {}}; + //noinspection TypeScriptUnresolvedFunction + navigate = jasmine.createSpy('navigate'); + parseUrl = jasmine.createSpy('parseUrl'); + events = new Observable((observer) => { + this.eventArr.forEach((e) => { + observer.next(e); + }); + observer.complete(); + }); + eventArr: any; + + // Stub constructor takes array of event objects. + constructor( events: any = observableOf({})) { + this.eventArr = events; + } + + navigateByUrl(url): void { + this.url = url; + } +}