Skip to content

Commit

Permalink
feat: save connection info, logout button (#285)
Browse files Browse the repository at this point in the history
  • Loading branch information
Helias authored and FrancescoBorzi committed Dec 25, 2019
1 parent 2844db2 commit d6aa1cc
Show file tree
Hide file tree
Showing 21 changed files with 462 additions and 5 deletions.
4 changes: 4 additions & 0 deletions src/app/components/app.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { MockedElectronService, MockedMysqlService } from '../test-utils/mocks';
import { MysqlService } from '../services/mysql.service';
import { ConnectionWindowComponent } from './connection-window/connection-window.component';
import { QueryErrorComponent } from './editors/shared/query-output/query-error/query-error.component';
import { ModalConfirmModule } from './editors/shared/modal-confirm/modal-confirm.module';
import { LogoutBtnComponent } from './main-window/sidebar/logout-btn/logout-btn.component';

describe('AppComponent', () => {
let component: AppComponent;
Expand All @@ -26,13 +28,15 @@ describe('AppComponent', () => {
AppComponent,
SidebarComponent,
QueryErrorComponent,
LogoutBtnComponent,
],
imports: [
FormsModule,
ReactiveFormsModule,
RouterTestingModule,
BrowserAnimationsModule,
PerfectScrollbarModule,
ModalConfirmModule,
],
providers: [
{ provide : ElectronService, useValue: instance(MockedElectronService) },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { async, ComponentFixture, TestBed, tick, fakeAsync } from '@angular/core/testing';
import { instance, reset } from 'ts-mockito';
import { MysqlError } from 'mysql';
import { of, throwError } from 'rxjs';
Expand All @@ -9,6 +9,7 @@ import { MockedMysqlService } from '../../test-utils/mocks';
import { MysqlService } from '../../services/mysql.service';
import { PageObject } from '../../test-utils/page-object';
import { ConnectionWindowModule } from './connection-window.module';
import { LocalStorageService } from '../../services/local-storage.service';

class ConnectionWindowComponentPage extends PageObject<ConnectionWindowComponent> {
get hostInput() { return this.query<HTMLInputElement>('#host'); }
Expand Down Expand Up @@ -46,9 +47,12 @@ describe('ConnectionWindowComponent', () => {
fixture.detectChanges();
});

it('clicking on the connect button without altering the default values should correctly work', () => {
it('clicking on the connect button without altering the default values should correctly work', fakeAsync(() => {
TestBed.get(LocalStorageService).clear();
component.error = { code: 'some previous error', errno: 1234 } as MysqlError;

tick();

page.clickElement(page.connectBtn);

expect(connectSpy).toHaveBeenCalledTimes(1);
Expand All @@ -61,7 +65,38 @@ describe('ConnectionWindowComponent', () => {
});
expect(component.error).toBeNull();
expect(page.errorElement.innerHTML).not.toContain('error-box');
});
}));

it('clicking on the connect button altering the default values using localStorage should correctly work', fakeAsync(() => {
const mockLocalStorage = {
'host': '127.0.0.1',
'port': '3306',
'user': 'Helias',
'keira3String': btoa('root'),
'database': 'shin_world',
};

TestBed.get(LocalStorageService).setItem('config', JSON.stringify(mockLocalStorage));
component.ngOnInit();

component.error = { code: 'some previous error', errno: 1234 } as MysqlError;

tick();

page.clickElement(page.connectBtn);

expect(connectSpy).toHaveBeenCalledTimes(1);
expect(connectSpy).toHaveBeenCalledWith({
'host': '127.0.0.1',
'port': '3306',
'user': 'Helias',
'password': 'root',
'database': 'shin_world',
});

expect(component.error).toBeNull();
expect(page.errorElement.innerHTML).not.toContain('error-box');
}));

it('filling the form and clicking on the connect button should correctly work', () => {
const host = '192.168.1.100';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { version } from '../../../../package.json';

import { MysqlService } from '../../services/mysql.service';
import { SubscriptionHandler } from '../../utils/subscription-handler/subscription-handler';
import { Config } from '../../types/config.type';
import { LocalStorageService } from '../../services/local-storage.service';

@Component({
selector: 'app-connection-window',
Expand All @@ -14,32 +16,57 @@ import { SubscriptionHandler } from '../../utils/subscription-handler/subscripti
export class ConnectionWindowComponent extends SubscriptionHandler implements OnInit {

public readonly KEIRA_VERSION = version;
private configStorage: Config;
form: FormGroup;
error: MysqlError;

constructor(
private mysqlService: MysqlService,
private localstorageService: LocalStorageService,
) {
super();
}

ngOnInit() {

this.form = new FormGroup({
'host': new FormControl('127.0.0.1'),
'port': new FormControl('3306'),
'user': new FormControl('root'),
'password': new FormControl('root'),
'database': new FormControl('acore_world'),
});

this.configStorage = JSON.parse(localStorage.getItem('config'));

if (!!this.configStorage) {
this.form.setValue({
host: this.configStorage.host,
port: this.configStorage.port,
user: this.configStorage.user,
password: atob(this.configStorage.keira3String),
database: this.configStorage.database,
});
}
}

onConnect() {
const tmpValues = this.form.getRawValue();
this.configStorage = {
host: tmpValues.host,
port: tmpValues.port,
user: tmpValues.user,
keira3String: btoa(tmpValues.password),
database: tmpValues.database,
};
this.localstorageService.setItem('config', JSON.stringify(this.configStorage));

this.subscriptions.push(
this.mysqlService.connect(this.form.getRawValue()).subscribe(() => {
this.error = null;
}, (error: MysqlError) => {
this.error = error;
})
);
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<div class="alert-box">
<div class="modal-header">
<h4 class="modal-title">{{ title }}</h4>
<button type="button" class="close" aria-label="Close" (click)="onCancel()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
{{ content }}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" (click)="onConfirm()" id="yes">Yes</button>
<button type="button" class="btn btn-secondary" (click)="onCancel()" id="no">No</button>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { BsModalRef } from 'ngx-bootstrap';
import Spy = jasmine.Spy;
import { ModalConfirmComponent } from './modal-confirm.component';
import { ModalConfirmModule } from './modal-confirm.module';
import { PageObject } from '../../../../test-utils/page-object';

class ModalConfirmComponentPage extends PageObject<ModalConfirmComponent> {
get yesBtn() { return this.query<HTMLButtonElement>('#yes'); }
get noBtn() { return this.query<HTMLButtonElement>('#no'); }
}

describe('ModalConfirmComponent', () => {
let component: ModalConfirmComponent;
let fixture: ComponentFixture<ModalConfirmComponent>;
let hideSpy: Spy;
let page: ModalConfirmComponentPage;

beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
ModalConfirmModule,
],
providers: [
BsModalRef,
],
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(ModalConfirmComponent);
component = fixture.componentInstance;
fixture.detectChanges();
page = new ModalConfirmComponentPage(fixture);

hideSpy = spyOn(TestBed.get(BsModalRef), 'hide');
});

it('onConfirm() should correctly hide the modal', () => {
const nextSpy = spyOn(component.onClose, 'next');

page.yesBtn.click();

expect(nextSpy).toHaveBeenCalledWith(true);
expect(nextSpy).toHaveBeenCalledTimes(1);
expect(hideSpy).toHaveBeenCalledTimes(1);
});

it('onCancel() should correctly hide the modal', () => {
const nextSpy = spyOn(component.onClose, 'next');

page.noBtn.click();

expect(nextSpy).toHaveBeenCalledWith(false);
expect(nextSpy).toHaveBeenCalledTimes(1);
expect(hideSpy).toHaveBeenCalledTimes(1);
});

});
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { BsModalRef } from 'ngx-bootstrap/modal';
import { OnInit, Component } from '@angular/core';
import { Subject } from 'rxjs';

@Component({
selector: 'app-modal-confirm',
templateUrl: './modal-confirm.component.html',
})
export class ModalConfirmComponent implements OnInit {

public onClose: Subject <boolean>;
title: string;
content: string;

constructor(private _bsModalRef: BsModalRef) {}

public ngOnInit(): void {
this.onClose = new Subject();
}

public onConfirm(): void {
this.onClose.next(true);
this._bsModalRef.hide();
}

public onCancel(): void {
this.onClose.next(false);
this._bsModalRef.hide();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { NgModule } from '@angular/core';
import { ModalModule } from 'ngx-bootstrap';
import { ModalConfirmComponent } from './modal-confirm.component';

@NgModule({
declarations: [ ModalConfirmComponent ],
imports: [ ModalModule.forRoot() ],
exports: [ ModalConfirmComponent ],
})
export class ModalConfirmModule {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<button class="btn btn-sm btn-secondary" (click)="openModalConfirm()">
Logout
<i class="fas fa-power-off"></i>
</button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
button.btn-sm {
font-size: 0.7rem;
margin-top: 6px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import Spy = jasmine.Spy;

import { LogoutBtnComponent } from './logout-btn.component';
import { LocationService } from '../../../../services/location.service';
import { ModalModule, BsModalService } from 'ngx-bootstrap';
import { NgModule } from '@angular/core';
import { ModalConfirmComponent } from '../../../editors/shared/modal-confirm/modal-confirm.component';

@NgModule({
declarations: [ ModalConfirmComponent ],
entryComponents: [ ModalConfirmComponent ],
imports: [ ],
})
class TestModule {}

describe('LogoutBtnComponent', () => {
let component: LogoutBtnComponent;
let fixture: ComponentFixture<LogoutBtnComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ LogoutBtnComponent ],
imports: [
ModalModule.forRoot(),
TestModule,
],
})
.compileComponents();

fixture = TestBed.createComponent(LogoutBtnComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));

it('openModalConfirm() should correctly work', () => {
const showSpy = spyOn(TestBed.get(BsModalService), 'show').and.callThrough();
const logoutSpy = spyOn(component, 'logout');

component.openModalConfirm();
expect(showSpy).toHaveBeenCalledTimes(1);

component['modalRef'].content.onCancel();
expect(logoutSpy).toHaveBeenCalledTimes(0);

component['modalRef'].content.onConfirm();
expect(logoutSpy).toHaveBeenCalledTimes(1);
});

it('logout() should correctly work', () => {
const locationServiceSpy: Spy = spyOn(TestBed.get(LocationService), 'reload');
component.logout();
expect(locationServiceSpy).toHaveBeenCalledTimes(1);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Component } from '@angular/core';

import { ModalConfirmComponent } from '../../../editors/shared/modal-confirm/modal-confirm.component';
import { BsModalService, BsModalRef } from 'ngx-bootstrap';
import { LocationService } from '../../../../services/location.service';
import { SubscriptionHandler } from '../../../../utils/subscription-handler/subscription-handler';

@Component({
selector: 'app-logout-btn',
templateUrl: './logout-btn.component.html',
styleUrls: ['./logout-btn.component.scss'],
})
export class LogoutBtnComponent extends SubscriptionHandler {

public modalRef: BsModalRef;
constructor(
private modalService: BsModalService,
private locationService: LocationService
) {
super();
}

openModalConfirm() {
const initialState = {
title: 'Logout',
content: 'Are you sure you want to logout?'
};

this.modalRef = this.modalService.show(ModalConfirmComponent, { initialState });

this.subscriptions.push(
this.modalRef.content.onClose.subscribe(result => {
if (result) {
this.logout();
}
})
);
}

logout() {
this.locationService.reload();
}

}
Loading

0 comments on commit d6aa1cc

Please sign in to comment.