Skip to content

Commit

Permalink
Merge 0ba23fc into b74ea20
Browse files Browse the repository at this point in the history
  • Loading branch information
FrancescoBorzi committed Aug 19, 2019
2 parents b74ea20 + 0ba23fc commit fa8c818
Show file tree
Hide file tree
Showing 17 changed files with 469 additions and 4 deletions.
@@ -0,0 +1,27 @@
<app-top-bar [handler]="handlerService"></app-top-bar>

<div class="container-fluid">

<span *ngIf="editorService.loading">Loading...</span>

<div *ngIf="editorService.form && !!editorService.loadedEntityId && !editorService.loading">

<app-query-output [editorService]="editorService" (executeQuery)="editorService.save($event)"></app-query-output>

<hr class="mt-2 mb-1">

<div class="wiki-link">
<a [href]="docUrl" target="_blank">
<i class="fas fa-link"></i> {{ editorService.entityTable }} documentation
</a>
</div>

<form
[formGroup]="editorService.form"
class="form-group edit-form"
>

</form>

</div>
</div>
Empty file.
@@ -0,0 +1,22 @@
import { Component } from '@angular/core';

import { SingleRowEditorComponent } from '../../shared/single-row-editor.component';
import { ItemTemplate } from '../../../../types/item-template.type';
import { ItemTemplateService } from '../../../../services/editors/item/item-template.service';
import { ItemHandlerService } from '../../../../services/handlers/item-handler.service';

@Component({
selector: 'app-item-template',
templateUrl: './item-template.component.html',
styleUrls: ['./item-template.component.scss']
})
export class ItemTemplateComponent extends SingleRowEditorComponent<ItemTemplate> {

/* istanbul ignore next */ // because of: https://github.com/gotwarlost/istanbul/issues/690
constructor(
public editorService: ItemTemplateService,
public handlerService: ItemHandlerService,
) {
super(editorService, handlerService);
}
}
Empty file.
@@ -0,0 +1,31 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { TooltipModule } from 'ngx-bootstrap';

import { TopBarModule } from '../../shared/top-bar/top-bar.module';
import { QueryOutputModule } from '../../shared/query-output/query-output.module';
import { ItemTemplateComponent } from './item-template.component';
import { SingleValueSelectorModule } from '../../shared/selectors/single-value-selector/single-value-selector.module';
import { FlagsSelectorModule } from '../../shared/selectors/flags-selector/flags-selector.module';
import { ItemSelectorModule } from '../../shared/selectors/item-selector/item-selector.module';

@NgModule({
declarations: [
ItemTemplateComponent,
],
imports: [
BrowserModule,
ReactiveFormsModule,
TopBarModule,
QueryOutputModule,
TooltipModule.forRoot(),
SingleValueSelectorModule,
FlagsSelectorModule,
ItemSelectorModule,
],
exports: [
ItemTemplateComponent,
],
})
export class ItemTemplateModule {}
5 changes: 4 additions & 1 deletion src/app/components/editors/item/item.module.ts
@@ -1,7 +1,10 @@
import { NgModule } from '@angular/core';
import { ItemTemplateModule } from './item-template/item-template.module';
import { SelectItemModule } from './select-item/select-item.module';

const modules = [

SelectItemModule,
ItemTemplateModule,
];

@NgModule({
Expand Down
@@ -0,0 +1,64 @@
<app-top-bar [handler]="handlerService"></app-top-bar>

<div class="container-fluid p-3">

<app-create
[entityTable]="entityTable"
[entityIdField]="entityIdField"
[customStartingId]="customStartingId"
[handlerService]="handlerService"
[queryService]="queryService"
></app-create>

<hr class="mt-2 mb-2">

<p>Or search and select an existing one:</p>
<form [formGroup]="selectService.queryForm">
<div class="row">
<ng-container [formGroup]="selectService.fields">
<div class="form-group col-2">
<input [formControlName]="'entry'" type="number" class="form-control form-control-sm" id="search-id" placeholder="Item ID">
</div>
<div class="form-group col-3">
<input [formControlName]="'name'" class="form-control form-control-sm" id="name" placeholder="Item name">
</div>
</ng-container>
<div class="form-group col-2">
<input [formControlName]="'limit'" class="form-control form-control-sm" id="limit" placeholder="Limit">
</div>
<div class="col-2">
<button
class="btn btn-primary btn-sm"
id="search-btn"
[disabled]="selectService.queryForm.invalid"
(click)="selectService.onSearch()"
>Search</button>
</div>
</div>
<code [highlight]="selectService.query"></code>
</form>

<div *ngIf="selectService.rows">

<ngx-datatable
class="bootstrap table table-striped text-center datatable-select"
[rows]="selectService.rows"
[headerHeight]="DTCFG.headerHeight"
[footerHeight]="DTCFG.footerHeight"
[columnMode]="DTCFG.columnMode"
[rowHeight]="DTCFG.rowHeight"
[limit]="DTCFG.limit"
[selectionType]="DTCFG.selectionType"
(select)='selectService.onSelect($event)'
[count]="false"
>
<ngx-datatable-column name="ID" prop="ID" [minWidth]="100">
<ng-template let-row="row" ngx-datatable-cell-template>
{{ row.entry }}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name="name" prop="name" [minWidth]="60"></ngx-datatable-column>
</ngx-datatable>

</div>
</div>
Empty file.
@@ -0,0 +1,35 @@
import { Component, } from '@angular/core';

import { SelectComponent } from '../../shared/select.component';
import {
ITEM_TEMPLATE_CUSTOM_STARTING_ID,
ITEM_TEMPLATE_ID,
ITEM_TEMPLATE_TABLE,
ItemTemplate
} from '../../../../types/item-template.type';
import { ItemSelectService } from '../../../../services/select/item-select.service';
import { ItemHandlerService } from '../../../../services/handlers/item-handler.service';
import { QueryService } from '../../../../services/query.service';

@Component({
selector: 'app-select-item',
templateUrl: './select-item.component.html',
styleUrls: ['./select-item.component.scss']
})
export class SelectItemComponent extends SelectComponent<ItemTemplate> {
/* istanbul ignore next */ // because of: https://github.com/gotwarlost/istanbul/issues/690
constructor(
public selectService: ItemSelectService,
public handlerService: ItemHandlerService,
public queryService: QueryService,
) {
super(
ITEM_TEMPLATE_TABLE,
ITEM_TEMPLATE_ID,
ITEM_TEMPLATE_CUSTOM_STARTING_ID,
selectService,
handlerService,
queryService,
);
}
}
@@ -0,0 +1,170 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { Router } from '@angular/router';
import { of } from 'rxjs';
import Spy = jasmine.Spy;

import { QueryService } from '../../../../services/query.service';
import { SelectItemComponent } from './select-item.component';
import { ItemSelectService } from '../../../../services/select/item-select.service';
import { SelectItemModule } from './select-item.module';
import { ItemTemplate } from '../../../../types/item-template.type';
import { SelectPageObject } from '../../../../test-utils/select-page-object';

class SelectItemComponentPage extends SelectPageObject<SelectItemComponent> {
ID_FIELD = 'entry';
}

describe('SelectItem integration tests', () => {
let component: SelectItemComponent;
let fixture: ComponentFixture<SelectItemComponent>;
let selectService: ItemSelectService;
let page: SelectItemComponentPage;
let queryService: QueryService;
let querySpy: Spy;
let navigateSpy: Spy;

const value = 1200;

beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
SelectItemModule,
RouterTestingModule,
],
})
.compileComponents();
}));

beforeEach(() => {
navigateSpy = spyOn(TestBed.get(Router), 'navigate');
queryService = TestBed.get(QueryService);
querySpy = spyOn(queryService, 'query').and.returnValue(of(
{ results: [{ max: 1 }] }
));

selectService = TestBed.get(ItemSelectService);

fixture = TestBed.createComponent(SelectItemComponent);
page = new SelectItemComponentPage(fixture);
component = fixture.componentInstance;
fixture.autoDetectChanges(true);
fixture.detectChanges();
});

it('should correctly initialise', async(() => {
fixture.whenStable().then(() => {
expect(page.createInput.value).toEqual(`${component.customStartingId}`);
page.expectNewEntityFree();
expect(querySpy).toHaveBeenCalledWith(
'SELECT MAX(entry) AS max FROM item_template;'
);
expect(page.queryWrapper.innerText).toContain(
'SELECT * FROM `item_template` LIMIT 100'
);
});
}));

it('should correctly behave when inserting and selecting free id', async(() => {
fixture.whenStable().then(() => {
querySpy.calls.reset();
querySpy.and.returnValue(of(
{ results: [] }
));

page.setInputValue(page.createInput, value);

expect(querySpy).toHaveBeenCalledTimes(1);
expect(querySpy).toHaveBeenCalledWith(
`SELECT * FROM \`item_template\` WHERE (entry = ${value})`
);
page.expectNewEntityFree();

page.clickElement(page.selectNewBtn);

expect(navigateSpy).toHaveBeenCalledTimes(1);
expect(navigateSpy).toHaveBeenCalledWith(['item/item-template']);
page.expectTopBarCreatingNew(value);
});
}));

it('should correctly behave when inserting an existing entity', async(() => {
fixture.whenStable().then(() => {
querySpy.calls.reset();
querySpy.and.returnValue(of(
{ results: ['mock value'] }
));

page.setInputValue(page.createInput, value);

expect(querySpy).toHaveBeenCalledTimes(1);
expect(querySpy).toHaveBeenCalledWith(
`SELECT * FROM \`item_template\` WHERE (entry = ${value})`
);
page.expectEntityAlreadyInUse();
});
}));

for (const { testId, id, name, limit, expectedQuery } of [
{
testId: 1, id: 1200, name: `The People's Militia`, limit: '100', expectedQuery:
'SELECT * FROM `item_template` WHERE (`entry` LIKE \'%1200%\') AND (`name` LIKE \'%The People\\\'s Militia%\') LIMIT 100'
},
{
testId: 2, id: '', name: `The People's Militia`, limit: '100', expectedQuery:
'SELECT * FROM `item_template` WHERE (`name` LIKE \'%The People\\\'s Militia%\') LIMIT 100'
},
{
testId: 3, id: '', name: `The People's Militia`, limit: '100', expectedQuery:
'SELECT * FROM `item_template` WHERE (`name` LIKE \'%The People\\\'s Militia%\') LIMIT 100'
},
{
testId: 4, id: 1200, name: '', limit: '', expectedQuery:
'SELECT * FROM `item_template` WHERE (`entry` LIKE \'%1200%\')'
},
]) {
it(`searching an existing entity should correctly work [${testId}]`, () => {
querySpy.calls.reset();
if (id) {
page.setInputValue(page.searchIdInput, id);
}
if (name) {
page.setInputValue(page.searchNameInput, name);
}
page.setInputValue(page.searchLimitInput, limit);

expect(page.queryWrapper.innerText).toContain(expectedQuery);

page.clickElement(page.searchBtn);

expect(querySpy).toHaveBeenCalledTimes(1);
expect(querySpy).toHaveBeenCalledWith(expectedQuery);
});
}

it('searching and selecting an existing entity from the datatable should correctly work', () => {
const results: Partial<ItemTemplate>[] = [
{ id: 1, name: 'An awesome Item 1', ItemType: 0, ItemLevel: 1, MinLevel: 10, ItemDescription: '' },
{ id: 2, name: 'An awesome Item 2', ItemType: 0, ItemLevel: 2, MinLevel: 20, ItemDescription: '' },
{ id: 3, name: 'An awesome Item 3', ItemType: 0, ItemLevel: 3, MinLevel: 30, ItemDescription: '' },
];
querySpy.calls.reset();
querySpy.and.returnValue(of({ results }));

page.clickElement(page.searchBtn);

const row0 = page.getDatatableRow(page.DT_SELECTOR, 0);
const row1 = page.getDatatableRow(page.DT_SELECTOR, 1);
const row2 = page.getDatatableRow(page.DT_SELECTOR, 2);

expect(row0.innerText).toContain(results[0].name);
expect(row1.innerText).toContain(results[1].name);
expect(row2.innerText).toContain(results[2].name);

page.clickElement(page.getDatatableCell(page.DT_SELECTOR, 1, 1));

expect(navigateSpy).toHaveBeenCalledTimes(1);
expect(navigateSpy).toHaveBeenCalledWith(['item/item-template']);
page.expectTopBarEditing(results[1].entry, results[1].name);
});
});
30 changes: 30 additions & 0 deletions src/app/components/editors/item/select-item/select-item.module.ts
@@ -0,0 +1,30 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { NgxDatatableModule } from '@swimlane/ngx-datatable';
import { HighlightModule } from 'ngx-highlightjs';

import { TopBarModule } from '../../shared/top-bar/top-bar.module';
import { QueryOutputModule } from '../../shared/query-output/query-output.module';
import { SelectItemComponent } from './select-item.component';
import { CreateModule } from '../../shared/create/create.module';
import { highlightOptions } from '../../../../config/highlight.config';

@NgModule({
declarations: [
SelectItemComponent,
],
imports: [
BrowserModule,
ReactiveFormsModule,
TopBarModule,
QueryOutputModule,
CreateModule,
HighlightModule.forRoot(highlightOptions),
NgxDatatableModule,
],
exports: [
SelectItemComponent,
],
})
export class SelectItemModule {}

0 comments on commit fa8c818

Please sign in to comment.