Add more ui ut

Signed-off-by: Yogi_Wang <yawang@vmware.com>
This commit is contained in:
Yogi_Wang 2019-12-11 14:50:01 +08:00
parent 6d80803dbb
commit d84733ea57
24 changed files with 626 additions and 129 deletions

View File

@ -17,6 +17,6 @@
<div class="modal-footer">
<span class="spinner spinner-inline loading-top" [hidden]="showProgress === false"></span>
<button type="button" class="btn" [class.btn-outline]="!isSuccess" [class.btn-primary]="isSuccess" (click)="close()">{{btnCancelCaption | translate}}</button>
<button *ngIf="!isSuccess" type="button" class="btn btn-primary" [disabled]="!isValid || showProgress" (click)="send()">{{'BUTTON.SEND' | translate}}</button>
<button *ngIf="!isSuccess" type="button" id="submit-btn" class="btn btn-primary" [disabled]="!isValid || showProgress" (click)="send()">{{'BUTTON.SEND' | translate}}</button>
</div>
</clr-modal>

View File

@ -5,19 +5,25 @@ import { ClarityModule } from "@clr/angular";
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { PasswordSettingService } from '../password-setting.service';
import { InlineAlertComponent } from '../../../shared/inline-alert/inline-alert.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { of } from 'rxjs';
describe('ForgotPasswordComponent', () => {
let component: ForgotPasswordComponent;
let fixture: ComponentFixture<ForgotPasswordComponent>;
let fakePasswordSettingService = null;
let fakePasswordSettingService = {
sendResetPasswordMail: () => of(null)
};
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ForgotPasswordComponent],
declarations: [ForgotPasswordComponent, InlineAlertComponent],
imports: [
FormsModule,
ClarityModule,
TranslateModule.forRoot()
TranslateModule.forRoot(),
BrowserAnimationsModule
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
providers: [
@ -26,14 +32,53 @@ describe('ForgotPasswordComponent', () => {
]
}).compileComponents();
}));
let el;
beforeEach(() => {
fixture = TestBed.createComponent(ForgotPasswordComponent);
component = fixture.componentInstance;
fixture.detectChanges();
component.inlineAlert = TestBed.createComponent(InlineAlertComponent).componentInstance;
component.open();
el = fixture.debugElement;
fixture.autoDetectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should validate email', async () => {
await fixture.whenStable();
let resetPwdInput: HTMLInputElement = fixture.nativeElement.querySelector('#reset_pwd_email');
expect(resetPwdInput).toBeTruthy();
resetPwdInput.value = '1234567';
resetPwdInput.dispatchEvent(new Event('input'));
resetPwdInput.dispatchEvent(new Event('blur'));
await fixture.whenStable();
const resetPwdError = fixture.nativeElement.querySelector('#reset_pwd_email-error');
expect(resetPwdError.innerText).toEqual(' TOOLTIP.EMAIL ');
// success
resetPwdInput.value = '1234567@qq.com';
resetPwdInput.dispatchEvent(new Event('input'));
resetPwdInput.dispatchEvent(new Event('blur'));
await fixture.whenStable();
const resetPwdError1 = fixture.nativeElement.querySelector('#reset_pwd_email-error');
expect(resetPwdError1).toBeNull();
});
it('should send email to back end', async () => {
await fixture.whenStable();
let resetPwdInput: HTMLInputElement = fixture.nativeElement.querySelector('#reset_pwd_email');
resetPwdInput.value = '1234567@qq.com';
resetPwdInput.dispatchEvent(new Event('input'));
resetPwdInput.dispatchEvent(new Event('blur'));
await fixture.whenStable();
expect(el.nativeElement.querySelector('#submit-btn').disabled).toBeFalsy();
const submitBtn = fixture.nativeElement.querySelector('#submit-btn');
submitBtn.dispatchEvent(new Event('click'));
await fixture.whenStable();
const alertText: HTMLSpanElement = fixture.nativeElement.querySelector('.alert-text');
expect(alertText.innerText).toEqual(' RESET_PWD.SUCCESS ');
});
});

View File

@ -33,7 +33,7 @@
</div>
<div class="modal-footer">
<span class="spinner spinner-inline loading-top" [hidden]="showProgress === false"></span>
<button type="button" class="btn btn-outline" (click)="close()">{{'BUTTON.CANCEL' | translate}}</button>
<button type="button" class="btn btn-primary" [disabled]="!isValid || showProgress" (click)="doOk()">{{'BUTTON.OK' | translate}}</button>
<button type="button" class="btn btn-outline" id="cancel-btn" (click)="close()">{{'BUTTON.CANCEL' | translate}}</button>
<button type="button" class="btn btn-primary" id="ok-btn" [disabled]="!isValid || showProgress" (click)="doOk()">{{'BUTTON.OK' | translate}}</button>
</div>
</clr-modal>

View File

@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { async, ComponentFixture, TestBed, flush } from '@angular/core/testing';
import { PasswordSettingService } from './password-setting.service';
import { SessionService } from '../../shared/session.service';
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service';
@ -8,20 +8,29 @@ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { FormsModule } from '@angular/forms';
import { InlineAlertComponent } from '../../shared/inline-alert/inline-alert.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { of } from 'rxjs';
describe('PasswordSettingComponent', () => {
let component: PasswordSettingComponent;
let fixture: ComponentFixture<PasswordSettingComponent>;
let fakePasswordSettingService = null;
let fakeSessionService = null;
let fakeMessageHandlerService = null;
let fakePasswordSettingService = {
changePassword: () => of(null)
};
let fakeSessionService = {
getCurrentUser: () => true
};
let fakeMessageHandlerService = {
showSuccess: () => { }
};
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
ClarityModule,
TranslateModule.forRoot(),
FormsModule
FormsModule,
BrowserAnimationsModule
],
declarations: [PasswordSettingComponent, InlineAlertComponent],
providers: [
@ -39,10 +48,85 @@ describe('PasswordSettingComponent', () => {
component = fixture.componentInstance;
component.inlineAlert =
TestBed.createComponent(InlineAlertComponent).componentInstance;
fixture.detectChanges();
component.oldPwd = "Harbor12345";
component.open();
fixture.autoDetectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should verify new Password invalid', async () => {
await fixture.whenStable();
const newPasswordInput: HTMLInputElement = fixture.nativeElement.querySelector("#newPassword");
newPasswordInput.value = "HarborHarbor";
newPasswordInput.dispatchEvent(new Event("input"));
await fixture.whenStable();
newPasswordInput.dispatchEvent(new Event("blur"));
await fixture.whenStable();
const newPasswordInputError: any = fixture.nativeElement.querySelector("#newPassword-error");
expect(newPasswordInputError.innerText)
.toEqual(' TOOLTIP.PASSWORD ');
});
it('should verify new Password valid', async () => {
await fixture.whenStable();
const newPasswordInput: HTMLInputElement = fixture.nativeElement.querySelector("#newPassword");
newPasswordInput.value = "Harbor123456";
newPasswordInput.dispatchEvent(new Event("input"));
await fixture.whenStable();
newPasswordInput.dispatchEvent(new Event("blur"));
await fixture.whenStable();
const newPasswordInputError: any = fixture.nativeElement.querySelector("#newPassword-error");
expect(newPasswordInputError)
.toBeNull();
});
it('should verify comfirm Password invalid', async () => {
await fixture.whenStable();
const newPasswordInput: HTMLInputElement = fixture.nativeElement.querySelector("#newPassword");
newPasswordInput.value = "Harbor123456";
newPasswordInput.dispatchEvent(new Event("blur"));
await fixture.whenStable();
const reNewPasswordInput: HTMLInputElement = fixture.nativeElement.querySelector("#reNewPassword");
reNewPasswordInput.value = "Harbor12345";
reNewPasswordInput.dispatchEvent(new Event("blur"));
await fixture.whenStable();
const reNewPasswordInputError: any = fixture.nativeElement.querySelector("#reNewPassword-error");
expect(reNewPasswordInputError.innerText)
.toEqual(' TOOLTIP.CONFIRM_PWD ');
});
it('should verify comfirm Password valid', async () => {
await fixture.whenStable();
const newPasswordInput: HTMLInputElement = fixture.nativeElement.querySelector("#newPassword");
newPasswordInput.value = "Harbor123456";
newPasswordInput.dispatchEvent(new Event("blur"));
await fixture.whenStable();
const reNewPasswordInput: HTMLInputElement = fixture.nativeElement.querySelector("#reNewPassword");
reNewPasswordInput.value = "Harbor123456";
reNewPasswordInput.dispatchEvent(new Event("input"));
reNewPasswordInput.dispatchEvent(new Event("blur"));
await fixture.whenStable();
const reNewPasswordInputError: any = fixture.nativeElement.querySelector("#reNewPassword-error");
expect(reNewPasswordInputError)
.toBeNull();
});
it('should save new password', async () => {
await fixture.whenStable();
const newPasswordInput: HTMLInputElement = fixture.nativeElement.querySelector("#newPassword");
newPasswordInput.value = "Harbor123456";
newPasswordInput.dispatchEvent(new Event("input"));
newPasswordInput.dispatchEvent(new Event("blur"));
await fixture.whenStable();
const reNewPasswordInput: HTMLInputElement = fixture.nativeElement.querySelector("#reNewPassword");
reNewPasswordInput.value = "Harbor123456";
reNewPasswordInput.dispatchEvent(new Event("input"));
reNewPasswordInput.dispatchEvent(new Event("blur"));
await fixture.whenStable();
const okBtn: HTMLButtonElement = fixture.nativeElement.querySelector("#ok-btn");
okBtn.dispatchEvent(new Event("click"));
await fixture.whenStable();
const newPasswordInput1: HTMLInputElement = fixture.nativeElement.querySelector("#newPassword");
expect(newPasswordInput1)
.toBeNull();
});
});

View File

@ -1,8 +1,11 @@
import { TestBed, inject } from '@angular/core/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { TestBed, inject, getTestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { PasswordSettingService } from './password-setting.service';
describe('PasswordSettingService', () => {
let injector: TestBed;
let service: PasswordSettingService;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
@ -10,9 +13,45 @@ describe('PasswordSettingService', () => {
],
providers: [PasswordSettingService]
});
injector = getTestBed();
service = injector.get(PasswordSettingService);
httpMock = injector.get(HttpTestingController);
});
it('should be created', inject([PasswordSettingService], (service: PasswordSettingService) => {
expect(service).toBeTruthy();
it('should be created', inject([PasswordSettingService], (service1: PasswordSettingService) => {
expect(service1).toBeTruthy();
}));
const mockPasswordSetting = {
old_password: 'string',
new_password: 'string1'
};
it('changePassword() should success', () => {
service.changePassword(1, mockPasswordSetting).subscribe((res) => {
expect(res).toEqual(null);
});
const req = httpMock.expectOne('/api/users/1/password');
expect(req.request.method).toBe('PUT');
req.flush(null);
});
it('sendResetPasswordMail() should return data', () => {
service.sendResetPasswordMail("123").subscribe((res) => {
expect(res).toEqual(null);
});
const req = httpMock.expectOne('/c/sendEmail?email=123');
expect(req.request.method).toBe('GET');
req.flush(null);
});
it('resetPassword() should return data', () => {
service.resetPassword('1234', 'Harbor12345').subscribe((res) => {
expect(res).toEqual(null);
});
const req = httpMock.expectOne('/c/reset');
expect(req.request.method).toBe('POST');
req.flush(null);
});
});

View File

@ -6,6 +6,9 @@ import { FormsModule } from '@angular/forms';
import { PasswordSettingService } from '../password-setting.service';
import { RouterTestingModule } from '@angular/router/testing';
import { MessageHandlerService } from '../../../shared/message-handler/message-handler.service';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ClarityModule } from '@clr/angular';
import { InlineAlertComponent } from '../../../shared/inline-alert/inline-alert.component';
describe('ResetPasswordComponent', () => {
let component: ResetPasswordComponent;
@ -18,9 +21,11 @@ describe('ResetPasswordComponent', () => {
imports: [
TranslateModule.forRoot(),
FormsModule,
RouterTestingModule
RouterTestingModule,
BrowserAnimationsModule,
ClarityModule
],
declarations: [ResetPasswordComponent],
declarations: [ResetPasswordComponent, InlineAlertComponent],
providers: [
TranslateService,
{ provide: PasswordSettingService, useValue: fakePasswordSettingService },
@ -33,7 +38,9 @@ describe('ResetPasswordComponent', () => {
beforeEach(() => {
fixture = TestBed.createComponent(ResetPasswordComponent);
component = fixture.componentInstance;
fixture.detectChanges();
component.inlineAlert = TestBed.createComponent(InlineAlertComponent).componentInstance;
component.open();
fixture.autoDetectChanges();
});
it('should create', () => {

View File

@ -37,7 +37,7 @@ export class ResetPasswordComponent implements OnInit {
resetOk: boolean = false;
confirmPwd: string = "";
@ViewChild("resetPwdForm", {static: false}) resetPwdForm: NgForm;
@ViewChild("resetPwdForm", {static: true}) resetPwdForm: NgForm;
@ViewChild(InlineAlertComponent, {static: false})
inlineAlert: InlineAlertComponent;

View File

@ -6,7 +6,7 @@
</div>
<div class="modal-footer">
<span class="spinner spinner-inline loading-top" [hidden]="inProgress === false"> </span>
<button type="button" class="btn btn-outline" (click)="close()">{{'BUTTON.CANCEL' | translate}}</button>
<button id="sign-up" type="button" class="btn btn-primary" [disabled]="!isValid || inProgress" (click)="create()">{{ 'BUTTON.SIGN_UP' | translate }}</button>
<button type="button" class="btn btn-outline" id="close-btn" (click)="close()">{{'BUTTON.CANCEL' | translate}}</button>
<button id="sign-up" type="button" id="create-btn" class="btn btn-primary" [disabled]="!isValid || inProgress" (click)="create()">{{ 'BUTTON.SIGN_UP' | translate }}</button>
</div>
</clr-modal>

View File

@ -8,20 +8,41 @@ import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { NewUserFormComponent } from '../../shared/new-user-form/new-user-form.component';
import { FormsModule } from '@angular/forms';
import { InlineAlertComponent } from '../../shared/inline-alert/inline-alert.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { of } from 'rxjs';
describe('SignUpComponent', () => {
let component: SignUpComponent;
let fixture: ComponentFixture<SignUpComponent>;
let fakeSessionService = null;
let fakeUserService = null;
let fakeSessionService = {
checkUserExisting: () => of(true)
};
let fakeUserService = {
addUser: () => of(null)
};
const mockUser = {
user_id: 1,
username: 'string',
realname: 'string',
email: 'string',
password: 'string',
comment: 'string',
deleted: false,
role_name: 'string',
role_id: 1,
has_admin_role: true,
reset_uuid: 'string',
creation_time: 'string',
update_time: 'string',
};
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [SignUpComponent, NewUserFormComponent, InlineAlertComponent],
imports: [
FormsModule,
ClarityModule,
TranslateModule.forRoot()
TranslateModule.forRoot(),
BrowserAnimationsModule
],
providers: [
TranslateService,
@ -39,10 +60,35 @@ describe('SignUpComponent', () => {
TestBed.createComponent(NewUserFormComponent).componentInstance;
component.inlineAlert =
TestBed.createComponent(InlineAlertComponent).componentInstance;
fixture.detectChanges();
component.opened = true;
fixture.autoDetectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should close when no form change', async () => {
component.open();
await fixture.whenStable();
const closeBtn: HTMLButtonElement = fixture.nativeElement.querySelector("#close-btn");
expect(closeBtn).toBeTruthy();
closeBtn.dispatchEvent(new Event('click'));
await fixture.whenStable();
const closeBtn1: HTMLButtonElement = fixture.nativeElement.querySelector("#close-btn");
expect(closeBtn1).toBeNull();
});
it('should create new user', async () => {
component.open();
component.getNewUser = () => mockUser;
await fixture.whenStable();
const createBtn = fixture.nativeElement.querySelector('#create-btn');
createBtn.dispatchEvent(new Event('click'));
await fixture.whenStable();
const closeBtn1: HTMLButtonElement = fixture.nativeElement.querySelector("#close-btn");
expect(closeBtn1).toBeNull();
});
});

View File

@ -1,12 +1,17 @@
import { TestBed, inject } from '@angular/core/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { TestBed, inject, getTestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { CookieService } from 'ngx-cookie';
import { AppConfigService } from './app-config.service';
import { AppConfig } from './app-config';
import { Component } from '@angular/core';
describe('AppConfigService', () => {
let injector: TestBed;
let service: AppConfigService;
let httpMock: HttpTestingController;
let fakeCookieService = {
get: function (key) {
return key;
return null;
}
};
@ -16,9 +21,27 @@ describe('AppConfigService', () => {
providers: [AppConfigService,
{ provide: CookieService, useValue: fakeCookieService }]
});
injector = getTestBed();
service = injector.get(AppConfigService);
httpMock = injector.get(HttpTestingController);
});
let systeminfo = new AppConfig();
it('should be created', inject([AppConfigService], (service1: AppConfigService) => {
expect(service1).toBeTruthy();
}));
it('load() should return data', () => {
service.load().subscribe((res) => {
expect(res).toEqual(systeminfo);
});
it('should be created', inject([AppConfigService], (service: AppConfigService) => {
expect(service).toBeTruthy();
}));
const req = httpMock.expectOne('/api/systeminfo');
expect(req.request.method).toBe('GET');
req.flush(systeminfo);
expect(service.getConfig()).toEqual(systeminfo);
expect(service.isIntegrationMode()).toBeFalsy();
expect(service.isLdapMode()).toBeFalsy();
expect(service.isHttpAuthMode()).toBeFalsy();
expect(service.isOidcMode()).toBeFalsy();
});
});

View File

@ -1,8 +1,15 @@
import { TestBed, inject } from '@angular/core/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { TestBed, inject, getTestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { GlobalSearchService } from './global-search.service';
import { Injector } from '@angular/core';
import { SearchResults } from './search-results';
describe('GlobalSearchService', () => {
let injector: TestBed;
let service: GlobalSearchService;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [GlobalSearchService],
@ -10,9 +17,22 @@ describe('GlobalSearchService', () => {
HttpClientTestingModule
]
});
injector = getTestBed();
service = injector.get(GlobalSearchService);
httpMock = injector.get(HttpTestingController);
});
it('should be created', inject([GlobalSearchService], (service: GlobalSearchService) => {
expect(service).toBeTruthy();
it('should be created', inject([GlobalSearchService], (service1: GlobalSearchService) => {
expect(service1).toBeTruthy();
}));
it('doSearch should return data', () => {
service.doSearch("library").subscribe((res) => {
expect(res).toEqual(new SearchResults());
});
const req = httpMock.expectOne('/api/search?q=library');
expect(req.request.method).toBe('GET');
req.flush(new SearchResults());
});
});

View File

@ -5,59 +5,97 @@ import { SearchTriggerService } from './search-trigger.service';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { AppConfigService } from './../../app-config.service';
import { ListProjectROComponent } from '../../shared/list-project-ro/list-project-ro.component';
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service';
import { SearchResultComponent } from './search-result.component';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { of } from 'rxjs';
import { AppConfig } from '../../app-config';
import { ClarityModule } from '@clr/angular';
describe('SearchResultComponent', () => {
let component: SearchResultComponent;
let fixture: ComponentFixture<SearchResultComponent>;
let fakeSearchResults = null;
let fakeGlobalSearchService = null;
let fakeAppConfigService = null;
const project = {
project_id: 1,
owner_id: 1,
name: 'library',
creation_time: Date,
creation_time_str: 'string',
deleted: 1,
owner_name: 'string',
togglable: true,
update_time: Date,
current_user_role_id: 1,
repo_count: 1,
chart_count: 1,
has_project_admin_role: true,
is_member: true,
role_name: 'string',
metadata: {
public: 'string',
enable_content_trust: 'string',
prevent_vul: 'string',
severity: 'string',
auto_scan: 'string',
retention_id: 1
}
};
let fakeGlobalSearchService = {
doSearch: () => of({
project: [project],
repository: [],
chart: []
})
};
let fakeAppConfigService = {
getConfig: () => new AppConfig()
};
let searchResult = "";
let fakeMessageHandlerService = null;
let fakeSearchTriggerService = {
searchTriggerChan$: {
pipe() {
return {
subscribe() {
}
searchTriggerChan$: of(searchResult),
searchCloseChan$: of(null),
clear: () => null
};
}
},
searchCloseChan$: {
subscribe() {
}
}
};
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
HttpClientTestingModule
HttpClientTestingModule,
ClarityModule
],
declarations: [SearchResultComponent],
declarations: [SearchResultComponent, ListProjectROComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
}).overrideComponent(SearchResultComponent, {
set: {
providers: [
TranslateService,
{ provide: GlobalSearchService, useValue: fakeGlobalSearchService },
{ provide: AppConfigService, useValue: fakeAppConfigService },
{ provide: MessageHandlerService, useValue: fakeMessageHandlerService },
{ provide: SearchTriggerService, useValue: fakeSearchTriggerService },
{ provide: SearchResults, fakeSearchResults }
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
{ provide: GlobalSearchService, useValue: fakeGlobalSearchService },
{ provide: SearchResults, useValue: fakeSearchResults }
]
}
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SearchResultComponent);
component = fixture.componentInstance;
fixture.detectChanges();
component.stateIndicator = true;
fixture.autoDetectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should search library', async () => {
searchResult = 'library';
component.doSearch(searchResult);
await fixture.whenStable();
expect(component.searchResults.project[0].name).toEqual('library');
});
});

View File

@ -140,7 +140,13 @@ export class SearchResultComponent implements OnInit, OnDestroy {
// Call search service to complete the search request
doSearch(term: string): void {
// Only search none empty term
// If term is empty, then clear the results
if (!term || term.trim() === "") {
this.searchResults.project = [];
this.searchResults.repository = [];
if (this.withHelmChart) {
this.searchResults.chart = [];
}
return;
}
// Do nothing if search is ongoing
@ -154,15 +160,6 @@ export class SearchResultComponent implements OnInit, OnDestroy {
this.currentTerm = term;
// If term is empty, then clear the results
if (term === "") {
this.searchResults.project = [];
this.searchResults.repository = [];
if (this.withHelmChart) {
this.searchResults.chart = [];
}
return;
}
// Show spinner
this.onGoing = true;

View File

@ -10,6 +10,16 @@ import { HarborShellComponent } from './harbor-shell.component';
import { ClarityModule } from "@clr/angular";
import { of } from 'rxjs';
import { ConfigScannerService } from "../../config/scanner/config-scanner.service";
import { modalEvents } from '../modal-events.const';
import { AccountSettingsModalComponent } from '../../account/account-settings/account-settings-modal.component';
import { PasswordSettingComponent } from '../../account/password-setting/password-setting.component';
import { AboutDialogComponent } from '../../shared/about-dialog/about-dialog.component';
import { FormsModule } from '@angular/forms';
import { MessageHandlerService } from '../../shared/message-handler/message-handler.service';
import { AccountSettingsModalService } from '../../account/account-settings/account-settings-modal-service.service';
import { PasswordSettingService } from '../../account/password-setting/password-setting.service';
import { SkinableConfig } from '../../skinable-config.service';
import { InlineAlertComponent } from '../../shared/inline-alert/inline-alert.component';
describe('HarborShellComponent', () => {
let component: HarborShellComponent;
@ -20,13 +30,18 @@ describe('HarborShellComponent', () => {
}
};
let fakeSearchTriggerService = {
searchTriggerChan$: {
subscribe: function () {
}
},
searchCloseChan$: {
subscribe: function () {
}
searchTriggerChan$: of('null')
,
searchCloseChan$: of(null)
};
let mockMessageHandlerService = null;
let mockAccountSettingsModalService = null;
let mockPasswordSettingService = null;
let mockSkinableConfig = {
getProject: function () {
return {
introduction: {}
};
}
};
let fakeAppConfigService = {
@ -56,15 +71,21 @@ describe('HarborShellComponent', () => {
RouterTestingModule,
TranslateModule.forRoot(),
ClarityModule,
BrowserAnimationsModule
BrowserAnimationsModule,
FormsModule
],
declarations: [HarborShellComponent],
declarations: [HarborShellComponent, AccountSettingsModalComponent
, PasswordSettingComponent, AboutDialogComponent, InlineAlertComponent],
providers: [
TranslateService,
{ provide: SessionService, useValue: fakeSessionService },
{ provide: SearchTriggerService, useValue: fakeSearchTriggerService },
{ provide: AppConfigService, useValue: fakeAppConfigService },
{ provide: ConfigScannerService, useValue: fakeConfigScannerService }
{ provide: ConfigScannerService, useValue: fakeConfigScannerService },
{ provide: MessageHandlerService, useValue: mockMessageHandlerService },
{ provide: AccountSettingsModalService, useValue: mockAccountSettingsModalService },
{ provide: PasswordSettingService, useValue: mockPasswordSettingService },
{ provide: SkinableConfig, useValue: mockSkinableConfig },
],
schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA]
}).compileComponents();
@ -74,10 +95,32 @@ describe('HarborShellComponent', () => {
fixture = TestBed.createComponent(HarborShellComponent);
component = fixture.componentInstance;
component.showScannerInfo = true;
fixture.detectChanges();
component.accountSettingsModal = TestBed.createComponent(AccountSettingsModalComponent).componentInstance;
component.accountSettingsModal.inlineAlert = TestBed.createComponent(InlineAlertComponent).componentInstance;
component.pwdSetting = TestBed.createComponent(PasswordSettingComponent).componentInstance;
component.aboutDialog = TestBed.createComponent(AboutDialogComponent).componentInstance;
fixture.autoDetectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should open users profile', async () => {
component.openModal({modalName: modalEvents.USER_PROFILE, modalFlag: false });
await fixture.whenStable();
const accountSettingsUsernameInput = fixture.nativeElement.querySelector("#account_settings_username");
expect(accountSettingsUsernameInput).toBeTruthy();
});
it('should open users changPwd', async () => {
component.openModal({modalName: modalEvents.CHANGE_PWD, modalFlag: false });
await fixture.whenStable();
const oldPasswordInput = fixture.nativeElement.querySelector("#oldPassword");
expect(oldPasswordInput).toBeTruthy();
});
it('should open users about-dialog', async () => {
component.openModal({modalName: modalEvents.ABOUT, modalFlag: false });
await fixture.whenStable();
const aboutVersionEl = fixture.nativeElement.querySelector(".about-version");
expect(aboutVersionEl).toBeTruthy();
});
});

View File

@ -399,7 +399,7 @@
[disabled]="!isValid() || !hasChanges()">{{'BUTTON.SAVE' | translate}}</button>
<button type="button" class="btn btn-outline" (click)="cancel()"
[disabled]="!isValid() || !hasChanges()">{{'BUTTON.CANCEL' | translate}}</button>
<button type="button" class="btn btn-outline" (click)="pingTestServer()" *ngIf="showTestingServerBtn"
<button type="button" id="ping-test" class="btn btn-outline" (click)="pingTestServer()" *ngIf="showTestingServerBtn"
[disabled]="!isConfigValidForTesting()">{{(showLdap?'BUTTON.TEST_LDAP':'BUTTON.TEST_OIDC') | translate}}</button>
<span id="forTestingLDAP" class="spinner spinner-inline" [hidden]="hideTestingSpinner"></span>
</div>

View File

@ -5,18 +5,29 @@ import { AppConfigService } from '../../app-config.service';
import { ConfigurationService } from '../config.service';
import { ConfigurationAuthComponent } from './config-auth.component';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { CUSTOM_ELEMENTS_SCHEMA, SimpleChange } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { of } from 'rxjs';
import { ErrorHandler } from "../../../lib/utils/error-handler";
import { SystemInfoService } from "../../../lib/services";
import { Configuration } from '../../../lib/components/config/config';
import { clone } from '../../../lib/utils/utils';
import { CONFIG_AUTH_MODE } from '../../../lib/entities/shared.const';
describe('ConfigurationAuthComponent', () => {
let component: ConfigurationAuthComponent;
let fixture: ComponentFixture<ConfigurationAuthComponent>;
let fakeMessageHandlerService = null;
let fakeConfigurationService = null;
let fakeAppConfigService = null;
let fakeMessageHandlerService = {
showSuccess: () => null
};
let fakeConfigurationService = {
saveConfiguration: () => of(null),
testLDAPServer: () => of(null),
testOIDCServer: () => of(null)
};
let fakeAppConfigService = {
load: () => of(null)
};
let fakeConfirmMessageService = null;
let fakeSystemInfoService = {
getSystemInfo: function () {
@ -49,10 +60,46 @@ describe('ConfigurationAuthComponent', () => {
beforeEach(() => {
fixture = TestBed.createComponent(ConfigurationAuthComponent);
component = fixture.componentInstance;
fixture.detectChanges();
(component as any).originalConfig = clone(component.currentConfig);
fixture.autoDetectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should save configuration', async () => {
const selfRegInput: HTMLInputElement = fixture.nativeElement.querySelector("#selfReg");
selfRegInput.dispatchEvent(new Event('click'));
component.currentConfig.self_registration.value = true;
await fixture.whenStable();
const configAuthSaveBtn: HTMLButtonElement = fixture.nativeElement.querySelector("#config_auth_save");
component.onGoing = true;
configAuthSaveBtn.dispatchEvent(new Event('click'));
await fixture.whenStable();
expect(component.onGoing).toBeFalsy();
});
it('should select ldap or uaa', () => {
component.handleOnChange({target: {value: 'ldap_auth'}});
expect(component.currentConfig.self_registration.value).toEqual(false);
});
it('should ping test server when ldap', async () => {
component.currentConfig.auth_mode.value = CONFIG_AUTH_MODE.LDAP_AUTH;
component.currentConfig.ldap_scope.value = 123456;
await fixture.whenStable();
const pingTestBtn = fixture.nativeElement.querySelector("#ping-test");
expect(pingTestBtn).toBeTruthy();
pingTestBtn.dispatchEvent(new Event('click'));
await fixture.whenStable();
expect(component.testingOnGoing).toBeFalsy();
});
it('should ping test server when oidc', async () => {
component.currentConfig.auth_mode.value = CONFIG_AUTH_MODE.OIDC_AUTH;
await fixture.whenStable();
const pingTestBtn = fixture.nativeElement.querySelector("#ping-test");
expect(pingTestBtn).toBeTruthy();
pingTestBtn.dispatchEvent(new Event('click'));
await fixture.whenStable();
expect(component.testingOnGoing).toBeFalsy();
});
});

View File

@ -8,17 +8,43 @@ import { ClarityModule } from "@clr/angular";
import { AppConfigService } from '../app-config.service';
import { ConfigurationService } from './config.service';
import { ConfigurationComponent } from './config.component';
import { of } from 'rxjs';
import { ConfirmationAcknowledgement } from '../shared/confirmation-dialog/confirmation-state-message';
import { ConfirmationState, ConfirmationTargets } from '../shared/shared.const';
import { Configuration } from '../../lib/components/config/config';
describe('ConfigurationComponent', () => {
let component: ConfigurationComponent;
let fixture: ComponentFixture<ConfigurationComponent>;
let fakeConfirmationDialogService = {
confirmationConfirm$: {
subscribe: function () {
}
}
let confirmationConfirmFlag = true;
let confirmationConfirm = () => {
return confirmationConfirmFlag ? of(new ConfirmationAcknowledgement(ConfirmationState.CONFIRMED, {}, ConfirmationTargets.CONFIG))
: of(new ConfirmationAcknowledgement(ConfirmationState.CONFIRMED
, {change: { email_password: 'Harbor12345' }, tabId: '1'}, ConfirmationTargets.CONFIG_TAB));
};
let fakeConfirmationDialogService = {
confirmationConfirm$: confirmationConfirm()
};
let mockConfigurationService = {
getConfiguration: () => of(new Configuration()),
confirmationConfirm$: of(new ConfirmationAcknowledgement(ConfirmationState.CONFIRMED, {}, ConfirmationTargets.CONFIG))
};
let fakeSessionService = {
getCurrentUser: function () {
return {
has_admin_role: true,
user_id: 1,
username: 'admin',
email: "",
realname: "admin",
role_name: "admin",
role_id: 1,
comment: "string",
};
},
updateAccountSettings: () => of(null),
renameAdmin: () => of(null),
};
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
@ -37,6 +63,7 @@ describe('ConfigurationComponent', () => {
}
},
{ provide: ConfirmationDialogService, useValue: fakeConfirmationDialogService },
{ provide: SessionService, useValue: fakeSessionService },
{ provide: MessageHandlerService, useValue: null },
{
provide: AppConfigService, useValue: {
@ -46,12 +73,7 @@ describe('ConfigurationComponent', () => {
}
},
{
provide: ConfigurationService, useValue: {
confirmationConfirm$: {
subscribe: function () {
}
}
}
provide: ConfigurationService, useValue: mockConfigurationService
}
]
}).compileComponents();
@ -66,4 +88,16 @@ describe('ConfigurationComponent', () => {
it('should create', () => {
expect(component).toBeTruthy();
});
it('should reset part of allConfig ', async () => {
confirmationConfirmFlag = false;
component.originalCopy.email_password.value = 'Harbor12345';
component.reset({
email_password: {
value: 'Harbor12345',
editable: true
}
});
await fixture.whenStable();
expect(component.allConfig.email_password.value).toEqual('Harbor12345');
});
});

View File

@ -70,13 +70,6 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
return this.appConfigService.getConfig().with_admiral;
}
isCurrentTabLink(tabId: string): boolean {
return this.currentTabId === tabId;
}
isCurrentTabContent(contentId: string): boolean {
return TabLinkContentMap[this.currentTabId] === contentId;
}
refreshAllconfig() {
this.retrieveConfig();
}
@ -124,10 +117,6 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
, error => console.error('Failed to reload bootstrap option with error: ', error));
}
public tabLinkClick(tabLink: string) {
this.currentTabId = tabLink;
}
retrieveConfig(): void {
this.onGoing = true;
this.configService.getConfiguration()

View File

@ -79,7 +79,7 @@
| translate}}</button>
<button type="button" class="btn btn-outline" (click)="cancel()" [disabled]="!isValid() || !hasChanges()">{{'BUTTON.CANCEL'
| translate}}</button>
<button type="button" class="btn btn-outline" (click)="testMailServer()" [disabled]="!isMailConfigValid()">{{'BUTTON.TEST_MAIL'
<button type="button" id="ping-test" class="btn btn-outline" (click)="testMailServer()" [disabled]="!isMailConfigValid()">{{'BUTTON.TEST_MAIL'
| translate}}</button>
<span id="forTestingMail" class="spinner spinner-inline" [hidden]="hideMailTestingSpinner"></span>
</div>

View File

@ -6,11 +6,19 @@ import { ConfigurationEmailComponent } from './config-email.component';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { clone } from '../../../lib/utils/utils';
import { of } from 'rxjs';
describe('ConfigurationEmailComponent', () => {
let component: ConfigurationEmailComponent;
let fixture: ComponentFixture<ConfigurationEmailComponent>;
let fakeConfigurationService = {
saveConfiguration: () => of(null),
testMailServer: () => of(null)
};
let fakeMessageHandlerService = {
showSuccess: () => null
};
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
@ -19,10 +27,10 @@ describe('ConfigurationEmailComponent', () => {
],
declarations: [ConfigurationEmailComponent],
providers: [
{ provide: MessageHandlerService, useValue: null },
{ provide: MessageHandlerService, useValue: fakeMessageHandlerService },
TranslateService,
{ provide: ConfirmMessageHandler, useValue: null },
{ provide: ConfigurationService, useValue: null }
{ provide: ConfigurationService, useValue: fakeConfigurationService }
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
}).compileComponents();
@ -31,10 +39,34 @@ describe('ConfigurationEmailComponent', () => {
beforeEach(() => {
fixture = TestBed.createComponent(ConfigurationEmailComponent);
component = fixture.componentInstance;
(component as any).originalConfig = clone(component.currentConfig);
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should save configuration', async () => {
component.currentConfig.email_host.value = 'smtp.mydomain.com';
component.currentConfig.email_port.value = 25;
component.currentConfig.email_from.value = 'smtp.mydomain.com';
await fixture.whenStable();
const configEmailSaveBtn: HTMLButtonElement = fixture.nativeElement.querySelector("#config_email_save");
component.onGoing = true;
configEmailSaveBtn.dispatchEvent(new Event('click'));
await fixture.whenStable();
expect(component.onGoing).toBeFalsy();
});
it('should ping test server', async () => {
component.currentConfig.email_host.value = 'smtp.mydomain.com';
component.currentConfig.email_port.value = 25;
component.currentConfig.email_from.value = 'smtp.mydomain.com';
await fixture.whenStable();
const pingTestBtn = fixture.nativeElement.querySelector("#ping-test");
expect(pingTestBtn).toBeTruthy();
pingTestBtn.dispatchEvent(new Event('click'));
await fixture.whenStable();
expect(component.testingMailOnGoing).toBeFalsy();
});
});

View File

@ -1,5 +1,5 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { async, ComponentFixture, TestBed, getTestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { DevCenterComponent } from './dev-center.component';
import { CookieService } from 'ngx-cookie';
@ -12,6 +12,9 @@ describe('DevCenterComponent', () => {
return "xsrf";
}
};
let cookie = "fdsa|ds";
let injector: TestBed;
let httpMock: HttpTestingController;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [DevCenterComponent],
@ -27,16 +30,25 @@ describe('DevCenterComponent', () => {
],
})
.compileComponents();
injector = getTestBed();
httpMock = injector.get(HttpTestingController);
}));
beforeEach(() => {
fixture = TestBed.createComponent(DevCenterComponent);
component = fixture.componentInstance;
fixture.detectChanges();
fixture.autoDetectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('get swagger should return data', () => {
const req = httpMock.expectOne('/swagger.json');
expect(req.request.method).toBe('GET');
req.flush({
"host": '122.33',
});
});
});

View File

@ -9,6 +9,7 @@ import { SessionService } from "./../../shared/session.service";
import { UserGroup } from "./../group";
import { AppConfigService } from "../../app-config.service";
import { AddGroupModalComponent } from './add-group-modal.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
describe('AddGroupModalComponent', () => {
let component: AddGroupModalComponent;
@ -38,6 +39,7 @@ describe('AddGroupModalComponent', () => {
imports: [
ClarityModule,
FormsModule,
BrowserAnimationsModule,
TranslateModule.forRoot()
],
schemas: [
@ -57,7 +59,8 @@ describe('AddGroupModalComponent', () => {
beforeEach(() => {
fixture = TestBed.createComponent(AddGroupModalComponent);
component = fixture.componentInstance;
fixture.detectChanges();
component.open();
fixture.autoDetectChanges();
});
it('should create', () => {

View File

@ -1,8 +1,27 @@
import { TestBed, inject } from '@angular/core/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { TestBed, inject, getTestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { SkinableConfig } from './skinable-config.service';
describe('SkinableConfig', () => {
let injector: TestBed;
let service: SkinableConfig;
let httpMock: HttpTestingController;
let product = {
"name": "",
"introduction": {
"zh-cn": "",
"es-es": "",
"en-us": ""
}
};
let mockCustomSkinData = {
"headerBgColor": "",
"headerLogo": "",
"loginBgImg": "",
"appTitle": "",
"product": product
};
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
@ -10,9 +29,26 @@ describe('SkinableConfig', () => {
],
providers: [SkinableConfig]
});
injector = getTestBed();
service = injector.get(SkinableConfig);
httpMock = injector.get(HttpTestingController);
});
it('should be created', inject([SkinableConfig], (service: SkinableConfig) => {
expect(service).toBeTruthy();
it('should be created', inject([SkinableConfig], (service1: SkinableConfig) => {
expect(service1).toBeTruthy();
}));
it('getCustomFile() should return data', () => {
service.getCustomFile().subscribe((res) => {
expect(res).toEqual(mockCustomSkinData);
});
const req = httpMock.expectOne('setting.json');
expect(req.request.method).toBe('GET');
req.flush(mockCustomSkinData);
expect(service.getSkinConfig()).toEqual(mockCustomSkinData);
expect(service.getProject()).toEqual(product);
service.customSkinData = null;
expect(service.getProject()).toBeNull();
});
});

View File

@ -70,6 +70,7 @@ export class Configuration {
ldap_group_attribute_name: StringValueItem;
ldap_group_search_scope: NumberValueItem;
ldap_group_membership_attribute: StringValueItem;
ldap_group_admin_dn: StringValueItem;
uaa_client_id: StringValueItem;
uaa_client_secret?: StringValueItem;
uaa_endpoint: StringValueItem;
@ -120,6 +121,7 @@ export class Configuration {
this.ldap_group_attribute_name = new StringValueItem("", true);
this.ldap_group_search_scope = new NumberValueItem(0, true);
this.ldap_group_membership_attribute = new StringValueItem("", true);
this.ldap_group_admin_dn = new StringValueItem("", true);
this.uaa_client_id = new StringValueItem("", true);
this.uaa_client_secret = new StringValueItem("", true);
this.uaa_endpoint = new StringValueItem("", true);