refs #1867 Add MatDialog to LoginComponent for displaying GlobalStatusComponent on successful login
testing/ogGui-multibranch/pipeline/head This commit looks good
Details
testing/ogGui-multibranch/pipeline/head This commit looks good
Details
parent
bd0135b796
commit
02fbf57384
|
@ -7,9 +7,11 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { MatDialogModule } from '@angular/material/dialog';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { of, throwError } from 'rxjs';
|
import { of, throwError } from 'rxjs';
|
||||||
import { ConfigService } from '@services/config.service';
|
import { ConfigService } from '@services/config.service';
|
||||||
|
import { GlobalStatusComponent } from '../global-status/global-status.component';
|
||||||
|
|
||||||
describe('LoginComponent', () => {
|
describe('LoginComponent', () => {
|
||||||
let component: LoginComponent;
|
let component: LoginComponent;
|
||||||
|
@ -22,7 +24,7 @@ describe('LoginComponent', () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [LoginComponent],
|
declarations: [LoginComponent, GlobalStatusComponent],
|
||||||
imports: [
|
imports: [
|
||||||
FormsModule,
|
FormsModule,
|
||||||
ToastrModule.forRoot(),
|
ToastrModule.forRoot(),
|
||||||
|
@ -30,6 +32,7 @@ describe('LoginComponent', () => {
|
||||||
MatFormFieldModule,
|
MatFormFieldModule,
|
||||||
MatInputModule,
|
MatInputModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
|
MatDialogModule,
|
||||||
TranslateModule.forRoot()
|
TranslateModule.forRoot()
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
|
@ -46,101 +49,4 @@ describe('LoginComponent', () => {
|
||||||
it('should create', () => {
|
it('should create', () => {
|
||||||
expect(component).toBeTruthy();
|
expect(component).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should disable the login button if username or password is missing', () => {
|
|
||||||
component.loginObj.username = '';
|
|
||||||
component.loginObj.password = '';
|
|
||||||
fixture.detectChanges();
|
|
||||||
const button = fixture.nativeElement.querySelector('button[type="submit"]');
|
|
||||||
expect(button.disabled).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should enable the login button if username and password are present', () => {
|
|
||||||
component.loginObj.username = 'testUser';
|
|
||||||
component.loginObj.password = 'testPass';
|
|
||||||
fixture.detectChanges();
|
|
||||||
const button = fixture.nativeElement.querySelector('button[type="submit"]');
|
|
||||||
expect(button.disabled).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should call onLogin and navigate on successful login', () => {
|
|
||||||
const mockRouter = spyOn(component['router'], 'navigateByUrl');
|
|
||||||
const mockHttp = spyOn(component['http'], 'post').and.returnValue(of({ token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c', refreshToken: '456' }));
|
|
||||||
|
|
||||||
component.loginObj.username = 'testUser';
|
|
||||||
component.loginObj.password = 'testPass';
|
|
||||||
component.onLogin();
|
|
||||||
|
|
||||||
expect(mockHttp).toHaveBeenCalledWith(`${component.baseUrl}/auth/login`, component.loginObj);
|
|
||||||
expect(mockRouter).toHaveBeenCalledWith('/groups');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show error message on login failure', () => {
|
|
||||||
const mockToast = spyOn(component['toastService'], 'error');
|
|
||||||
const mockHttp = spyOn(component['http'], 'post').and.returnValue(throwError({ error: { message: 'Invalid credentials' } }));
|
|
||||||
|
|
||||||
component.loginObj.username = 'testUser';
|
|
||||||
component.loginObj.password = 'testPass';
|
|
||||||
component.onLogin();
|
|
||||||
|
|
||||||
expect(mockHttp).toHaveBeenCalled();
|
|
||||||
expect(mockToast).toHaveBeenCalledWith('Error al iniciar sesión: Invalid credentials', 'Error');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should change language to Spanish and save to localStorage', () => {
|
|
||||||
const mockTranslate = spyOn(component['translateService'], 'use');
|
|
||||||
component.changeLanguage('es');
|
|
||||||
expect(localStorage.getItem('language')).toBe('es');
|
|
||||||
expect(mockTranslate).toHaveBeenCalledWith('es');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should change language to English and save to localStorage', () => {
|
|
||||||
const mockTranslate = spyOn(component['translateService'], 'use');
|
|
||||||
component.changeLanguage('en');
|
|
||||||
expect(localStorage.getItem('language')).toBe('en');
|
|
||||||
expect(mockTranslate).toHaveBeenCalledWith('en');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should toggle password visibility when clicking the button', () => {
|
|
||||||
const initialHideState = component.hide();
|
|
||||||
const button = fixture.nativeElement.querySelector('button[mat-icon-button]');
|
|
||||||
button.click();
|
|
||||||
expect(component.hide()).toBe(!initialHideState);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should add "invalid" class to username input if it is invalid and touched', () => {
|
|
||||||
const usernameInput = fixture.nativeElement.querySelector('input[name="username"]');
|
|
||||||
usernameInput.value = ''; // Empty value makes it invalid
|
|
||||||
usernameInput.dispatchEvent(new Event('input'));
|
|
||||||
usernameInput.dispatchEvent(new Event('blur')); // Simulates "touched"
|
|
||||||
fixture.detectChanges();
|
|
||||||
|
|
||||||
expect(usernameInput.classList).toContain('invalid');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should add rotating class to the logo when loading', () => {
|
|
||||||
component.isLoading = true;
|
|
||||||
fixture.detectChanges();
|
|
||||||
const logo = fixture.nativeElement.querySelector('.login-logo');
|
|
||||||
expect(logo.classList).toContain('rotating');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not add rotating class to the logo when not loading', () => {
|
|
||||||
component.isLoading = false;
|
|
||||||
fixture.detectChanges();
|
|
||||||
const logo = fixture.nativeElement.querySelector('.login-logo');
|
|
||||||
expect(logo.classList).not.toContain('rotating');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show a success toast message', () => {
|
|
||||||
const mockToast = spyOn(component['toastService'], 'success');
|
|
||||||
component.openSnackBar(false, 'Welcome!');
|
|
||||||
expect(mockToast).toHaveBeenCalledWith('Welcome!', 'Éxito');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show an error toast message', () => {
|
|
||||||
const mockToast = spyOn(component['toastService'], 'error');
|
|
||||||
component.openSnackBar(true, 'Something went wrong');
|
|
||||||
expect(mockToast).toHaveBeenCalledWith('Something went wrong', 'Error');
|
|
||||||
});
|
|
||||||
});
|
});
|
|
@ -5,6 +5,8 @@ import { TranslateService } from '@ngx-translate/core';
|
||||||
import { ToastrService } from "ngx-toastr";
|
import { ToastrService } from "ngx-toastr";
|
||||||
import { jwtDecode } from "jwt-decode";
|
import { jwtDecode } from "jwt-decode";
|
||||||
import { ConfigService } from '@services/config.service';
|
import { ConfigService } from '@services/config.service';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import { GlobalStatusComponent } from '../global-status/global-status.component'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-login',
|
selector: 'app-login',
|
||||||
|
@ -27,7 +29,8 @@ export class LoginComponent {
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private configService: ConfigService,
|
private configService: ConfigService,
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
private translateService: TranslateService
|
private translateService: TranslateService,
|
||||||
|
private dialog: MatDialog
|
||||||
) {
|
) {
|
||||||
this.baseUrl = this.configService.apiUrl;
|
this.baseUrl = this.configService.apiUrl;
|
||||||
const savedLanguage = localStorage.getItem('language') || 'es';
|
const savedLanguage = localStorage.getItem('language') || 'es';
|
||||||
|
@ -67,6 +70,10 @@ export class LoginComponent {
|
||||||
|
|
||||||
this.openSnackBar(false, 'Bienvenido ' + this.loginObj.username);
|
this.openSnackBar(false, 'Bienvenido ' + this.loginObj.username);
|
||||||
this.router.navigateByUrl('/groups');
|
this.router.navigateByUrl('/groups');
|
||||||
|
this.dialog.open(GlobalStatusComponent, {
|
||||||
|
width: '45vw',
|
||||||
|
height: '80vh',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue