diff --git a/libs/features/quest/src/quest-template-locale/quest-template-locale.component.html b/libs/features/quest/src/quest-template-locale/quest-template-locale.component.html index f5727560ead..9156f32cf6c 100644 --- a/libs/features/quest/src/quest-template-locale/quest-template-locale.component.html +++ b/libs/features/quest/src/quest-template-locale/quest-template-locale.component.html @@ -18,6 +18,16 @@ +
+ + + +
diff --git a/libs/features/quest/src/quest-template-locale/quest-template-locale.component.ts b/libs/features/quest/src/quest-template-locale/quest-template-locale.component.ts index 5c3986f1fb5..c7ce7f2d92d 100644 --- a/libs/features/quest/src/quest-template-locale/quest-template-locale.component.ts +++ b/libs/features/quest/src/quest-template-locale/quest-template-locale.component.ts @@ -1,9 +1,9 @@ import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { EMOTE, QuestTemplateLocale } from '@keira/shared/acore-world-model'; +import { QUEST_LOCALE, QuestTemplateLocale } from '@keira/shared/acore-world-model'; import { MultiRowEditorComponent } from '@keira/shared/base-abstract-classes'; import { EditorButtonsComponent, QueryOutputComponent, TopBarComponent } from '@keira/shared/base-editor-components'; -import { GameobjectSelectorBtnComponent, SingleValueSelectorBtnComponent } from '@keira/shared/selectors'; +import { SingleValueSelectorBtnComponent } from '@keira/shared/selectors'; import { TranslateModule } from '@ngx-translate/core'; import { TooltipModule } from 'ngx-bootstrap/tooltip'; import { QuestHandlerService } from '../quest-handler.service'; @@ -30,16 +30,14 @@ import { NgxDatatableModule } from '@siemens/ngx-datatable'; SingleValueSelectorBtnComponent, QuestPreviewComponent, Model3DViewerComponent, - GameobjectSelectorBtnComponent, AsyncPipe, EditorButtonsComponent, NgxDatatableModule, ], }) export class QuestTemplateLocaleComponent extends MultiRowEditorComponent { - readonly EMOTE = EMOTE; - protected override readonly editorService = inject(QuestTemplateLocaleService); readonly handlerService = inject(QuestHandlerService); readonly questPreviewService = inject(QuestPreviewService); + protected readonly QUEST_LOCALE = QUEST_LOCALE; } diff --git a/libs/features/quest/src/quest-template-locale/quest-template-locale.integration.spec.ts b/libs/features/quest/src/quest-template-locale/quest-template-locale.integration.spec.ts new file mode 100644 index 00000000000..dbd1087fb6a --- /dev/null +++ b/libs/features/quest/src/quest-template-locale/quest-template-locale.integration.spec.ts @@ -0,0 +1,198 @@ +import { QuestTemplateLocale } from '@keira/shared/acore-world-model'; +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { MysqlQueryService } from '@keira/shared/db-layer'; +import { of } from 'rxjs'; +import { QuestPreviewService } from '../quest-preview/quest-preview.service'; +import { QuestHandlerService } from '../quest-handler.service'; +import { QuestTemplateLocaleComponent } from './quest-template-locale.component'; +import { MultiRowEditorPageObject, TranslateTestingModule } from '@keira/shared/test-utils'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { ToastrModule } from 'ngx-toastr'; +import { ModalModule } from 'ngx-bootstrap/modal'; +import { RouterTestingModule } from '@angular/router/testing'; +import { KEIRA_APP_CONFIG_TOKEN, KEIRA_MOCK_CONFIG } from '@keira/shared/config'; +import Spy = jasmine.Spy; + +class QuestTemplateLocalePage extends MultiRowEditorPageObject { } + +describe('QuestTemplateLocale integration tests', () => { + const id = 1234; + let fixture: ComponentFixture; + let queryService: MysqlQueryService; + let querySpy: Spy; + let handlerService: QuestHandlerService; + let page: QuestTemplateLocalePage; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + imports: [ + BrowserAnimationsModule, + ToastrModule.forRoot(), + ModalModule.forRoot(), + QuestTemplateLocaleComponent, + RouterTestingModule, + TranslateTestingModule, + ], + providers: [QuestHandlerService, { provide: KEIRA_APP_CONFIG_TOKEN, useValue: KEIRA_MOCK_CONFIG }], + }).compileComponents(); + })); + + function setup(creatingNew: boolean) { + const originalRow = new QuestTemplateLocale(); + originalRow.ID = id; + + handlerService = TestBed.inject(QuestHandlerService); + handlerService['_selected'] = `${id}`; + handlerService.isNew = creatingNew; + + queryService = TestBed.inject(MysqlQueryService); + querySpy = spyOn(queryService, 'query').and.returnValue(of([])); + spyOn(queryService, 'queryValue').and.returnValue(of()); + + spyOn(queryService, 'selectAll').and.returnValue(of(creatingNew ? [] : [originalRow])); + const initializeServicesSpy = spyOn(TestBed.inject(QuestPreviewService), 'initializeServices'); + if (creatingNew) { + initializeServicesSpy.and.callThrough(); + } + + fixture = TestBed.createComponent(QuestTemplateLocaleComponent); + page = new QuestTemplateLocalePage(fixture); + fixture.autoDetectChanges(true); + fixture.detectChanges(); + } + + describe('Creating new', () => { + beforeEach(() => setup(true)); + + it('should correctly initialise', () => { + page.expectDiffQueryToBeEmpty(); + page.expectFullQueryToBeEmpty(); + expect(page.formError.hidden).toBe(true); + expect(page.addNewRowBtn.disabled).toBe(false); + expect(page.deleteSelectedRowBtn.disabled).toBe(true); + expect(page.getInputById('id').disabled).toBe(true); + expect(page.getInputById('title').disabled).toBe(true); + expect(page.getInputById('details').disabled).toBe(true); + expect(page.getInputById('objectives').disabled).toBe(true); + expect(page.getInputById('end-text').disabled).toBe(true); + expect(page.getInputById('completed-text').disabled).toBe(true); + expect(page.getInputById('objective-text-1').disabled).toBe(true); + expect(page.getInputById('objective-text-2').disabled).toBe(true); + expect(page.getInputById('objective-text-3').disabled).toBe(true); + expect(page.getInputById('objective-text-4').disabled).toBe(true); + expect(page.getEditorTableRowsCount()).toBe(0); + }); + + it('should correctly update the unsaved status', () => { + expect(handlerService.isQuestTemplateLocaleUnsaved).toBe(false); + page.addNewRow(); + expect(handlerService.isQuestTemplateLocaleUnsaved).toBe(true); + page.deleteRow(); + expect(handlerService.isQuestTemplateLocaleUnsaved).toBe(false); + }); + + it('adding new rows and executing the query should correctly work', () => { + const expectedQuery = + 'DELETE FROM `quest_template_locale` WHERE (`ID` = 1234) AND (`locale` IN (\'0\', \'1\', \'2\'));\n' + + 'INSERT INTO `quest_template_locale` (`ID`, `locale`, `Title`, `Details`, `Objectives`, `EndText`, `CompletedText`, ' + + '`ObjectiveText1`, `ObjectiveText2`, `ObjectiveText3`, `ObjectiveText4`, `VerifiedBuild`) VALUES\n' + + "(1234, '0', '', '', '', '', '', '', '', '', '', 0),\n" + + "(1234, '1', '', '', '', '', '', '', '', '', '', 0),\n" + + "(1234, '2', '', '', '', '', '', '', '', '', '', 0);"; + querySpy.calls.reset(); + + page.addNewRow(); + expect(page.getEditorTableRowsCount()).toBe(1); + page.addNewRow(); + expect(page.getEditorTableRowsCount()).toBe(2); + page.addNewRow(); + expect(page.getEditorTableRowsCount()).toBe(3); + page.expectDiffQueryToContain(expectedQuery); + + page.clickExecuteQuery(); + expect(querySpy).toHaveBeenCalledTimes(1); + expect(querySpy.calls.mostRecent().args[0]).toContain(expectedQuery); + }); + + it('adding a row and changing its values should correctly update the queries', () => { + page.addNewRow(); + page.expectDiffQueryToContain( + 'DELETE FROM `quest_template_locale` WHERE (`ID` = 1234) AND (`locale` IN (\'0\'));\n' + + 'INSERT INTO `quest_template_locale` (`ID`, `locale`, `Title`, `Details`, `Objectives`, `EndText`, `CompletedText`, ' + + '`ObjectiveText1`, `ObjectiveText2`, `ObjectiveText3`, `ObjectiveText4`, `VerifiedBuild`) VALUES\n' + + "(1234, '0', '', '', '', '', '', '', '', '', '', 0);", + ); + page.expectFullQueryToContain( + 'DELETE FROM `quest_template_locale` WHERE (`ID` = 1234);\n' + + 'INSERT INTO `quest_template_locale` (`ID`, `locale`, `Title`, `Details`, `Objectives`, `EndText`, `CompletedText`, ' + + '`ObjectiveText1`, `ObjectiveText2`, `ObjectiveText3`, `ObjectiveText4`, `VerifiedBuild`) VALUES\n' + + "(1234, '0', '', '', '', '', '', '', '', '', '', 0);", + ); + + page.setInputValueById('title', 'test'); + page.expectDiffQueryToContain( + 'DELETE FROM `quest_template_locale` WHERE (`ID` = 1234) AND (`locale` IN (\'0\'));\n' + + 'INSERT INTO `quest_template_locale` (`ID`, `locale`, `Title`, `Details`, `Objectives`, `EndText`, `CompletedText`, ' + + '`ObjectiveText1`, `ObjectiveText2`, `ObjectiveText3`, `ObjectiveText4`, `VerifiedBuild`) VALUES\n' + + "(1234, '0', 'test', '', '', '', '', '', '', '', '', 0);", + ); + page.expectFullQueryToContain( + 'DELETE FROM `quest_template_locale` WHERE (`ID` = 1234);\n' + + 'INSERT INTO `quest_template_locale` (`ID`, `locale`, `Title`, `Details`, `Objectives`, `EndText`, `CompletedText`, ' + + '`ObjectiveText1`, `ObjectiveText2`, `ObjectiveText3`, `ObjectiveText4`, `VerifiedBuild`) VALUES\n' + + "(1234, '0', 'test', '', '', '', '', '', '', '', '', 0);", + ); + + page.setInputValueById('completed-text', 'test2'); + page.expectDiffQueryToContain( + 'DELETE FROM `quest_template_locale` WHERE (`ID` = 1234) AND (`locale` IN (\'0\'));\n' + + 'INSERT INTO `quest_template_locale` (`ID`, `locale`, `Title`, `Details`, `Objectives`, `EndText`, `CompletedText`, ' + + '`ObjectiveText1`, `ObjectiveText2`, `ObjectiveText3`, `ObjectiveText4`, `VerifiedBuild`) VALUES\n' + + "(1234, '0', 'test', '', '', '', 'test2', '', '', '', '', 0);", + ); + page.expectFullQueryToContain( + 'DELETE FROM `quest_template_locale` WHERE (`ID` = 1234);\n' + + 'INSERT INTO `quest_template_locale` (`ID`, `locale`, `Title`, `Details`, `Objectives`, `EndText`, `CompletedText`, ' + + '`ObjectiveText1`, `ObjectiveText2`, `ObjectiveText3`, `ObjectiveText4`, `VerifiedBuild`) VALUES\n' + + "(1234, '0', 'test', '', '', '', 'test2', '', '', '', '', 0);", + ); + + page.setInputValueById('locale', 'deDE'); + page.expectDiffQueryToContain( + 'DELETE FROM `quest_template_locale` WHERE (`ID` = 1234) AND (`locale` IN (\'deDE\'));\n' + + 'INSERT INTO `quest_template_locale` (`ID`, `locale`, `Title`, `Details`, `Objectives`, `EndText`, `CompletedText`, ' + + '`ObjectiveText1`, `ObjectiveText2`, `ObjectiveText3`, `ObjectiveText4`, `VerifiedBuild`) VALUES\n' + + "(1234, 'deDE', 'test', '', '', '', 'test2', '', '', '', '', 0);", + ); + page.expectFullQueryToContain( + 'DELETE FROM `quest_template_locale` WHERE (`ID` = 1234);\n' + + 'INSERT INTO `quest_template_locale` (`ID`, `locale`, `Title`, `Details`, `Objectives`, `EndText`, `CompletedText`, ' + + '`ObjectiveText1`, `ObjectiveText2`, `ObjectiveText3`, `ObjectiveText4`, `VerifiedBuild`) VALUES\n' + + "(1234, 'deDE', 'test', '', '', '', 'test2', '', '', '', '', 0);", + ); + }); + + it('adding a row changing its values and duplicate it should correctly update the queries', () => { + page.addNewRow(); + page.setInputValueById('title', '1'); + page.setInputValueById('completed-text', '2'); + page.setInputValueById('locale', 'deDE'); + page.duplicateSelectedRow(); + + page.expectDiffQueryToContain( + 'DELETE FROM `quest_template_locale` WHERE (`ID` = 1234) AND (`locale` IN (\'deDE\', \'0\'));\n' + + 'INSERT INTO `quest_template_locale` (`ID`, `locale`, `Title`, `Details`, `Objectives`, `EndText`, `CompletedText`, ' + + '`ObjectiveText1`, `ObjectiveText2`, `ObjectiveText3`, `ObjectiveText4`, `VerifiedBuild`) VALUES\n' + + "(1234, 'deDE', '1', '', '', '', '2', '', '', '', '', 0),\n" + + "(1234, '0', '1', '', '', '', '2', '', '', '', '', 0);", + ); + page.expectFullQueryToContain( + 'DELETE FROM `quest_template_locale` WHERE (`ID` = 1234);\n' + + 'INSERT INTO `quest_template_locale` (`ID`, `locale`, `Title`, `Details`, `Objectives`, `EndText`, `CompletedText`, ' + + '`ObjectiveText1`, `ObjectiveText2`, `ObjectiveText3`, `ObjectiveText4`, `VerifiedBuild`) VALUES\n' + + "(1234, 'deDE', '1', '', '', '', '2', '', '', '', '', 0),\n" + + "(1234, '0', '1', '', '', '', '2', '', '', '', '', 0);", + ); + }); + }); +}); diff --git a/libs/features/quest/src/quest-template-locale/quest-template-locale.service.spec.ts b/libs/features/quest/src/quest-template-locale/quest-template-locale.service.spec.ts new file mode 100644 index 00000000000..357b5fe0ace --- /dev/null +++ b/libs/features/quest/src/quest-template-locale/quest-template-locale.service.spec.ts @@ -0,0 +1,27 @@ +import { TestBed } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; +import { MysqlQueryService, SqliteService } from '@keira/shared/db-layer'; +import { instance, mock } from 'ts-mockito'; +import { ToastrService } from 'ngx-toastr'; +import { QuestTemplateLocaleService } from './quest-template-locale.service'; +import { QuestHandlerService } from '../quest-handler.service'; + +describe('QuestTemplateLocaleService', () => { + beforeEach(() => + TestBed.configureTestingModule({ + imports: [RouterTestingModule], + providers: [ + { provide: MysqlQueryService, useValue: instance(mock(MysqlQueryService)) }, + { provide: ToastrService, useValue: instance(mock(ToastrService)) }, + { provide: SqliteService, useValue: instance(mock(SqliteService)) }, + QuestHandlerService, + QuestTemplateLocaleService, + ], + }), + ); + + it('should be created', () => { + const service: QuestTemplateLocaleService = TestBed.inject(QuestTemplateLocaleService); + expect(service).toBeTruthy(); + }); +}); diff --git a/libs/shared/acore-world-model/src/entities/quest-template-locale.type.ts b/libs/shared/acore-world-model/src/entities/quest-template-locale.type.ts index 60cd948c16b..5fbf468aa49 100644 --- a/libs/shared/acore-world-model/src/entities/quest-template-locale.type.ts +++ b/libs/shared/acore-world-model/src/entities/quest-template-locale.type.ts @@ -1,9 +1,19 @@ -import { TableRow } from '@keira/shared/constants'; +import { Option, TableRow } from '@keira/shared/constants'; export const QUEST_TEMPLATE_LOCALE_TABLE = 'quest_template_locale'; export const QUEST_TEMPLATE_LOCALE_ID = 'ID'; export const QUEST_TEMPLATE_LOCALE_ID_2 = 'locale'; +export const QUEST_LOCALE: Option[] = [ + { value: 'deDE', name: 'German (Germany)' }, + { value: 'esES', name: 'Spanish (Spain)' }, + { value: 'esMX', name: 'Spanish (Mexico)' }, + { value: 'frFR', name: 'French (France)' }, + { value: 'ruRU', name: 'Russian (Russia)' }, + { value: 'zhCN', name: 'Chinese (China)' }, + { value: 'zhTW', name: 'Chinese (Taiwan)' } +]; + export class QuestTemplateLocale extends TableRow { ID: number = 0; locale: string = ''; diff --git a/libs/shared/base-abstract-classes/src/service/editors/multi-row-editor.service.ts b/libs/shared/base-abstract-classes/src/service/editors/multi-row-editor.service.ts index bea6a2cf107..1c2f8c702ff 100644 --- a/libs/shared/base-abstract-classes/src/service/editors/multi-row-editor.service.ts +++ b/libs/shared/base-abstract-classes/src/service/editors/multi-row-editor.service.ts @@ -135,8 +135,10 @@ export abstract class MultiRowEditorService extends EditorSe } protected isRowIdTaken(id: number) { + const searchId = id.toString(); for (const row of this._newRows) { - if (row[this._entitySecondIdField] === id) { + const rowId = row[this._entitySecondIdField].toString(); + if (rowId === searchId) { return true; } } @@ -223,7 +225,10 @@ export abstract class MultiRowEditorService extends EditorSe if (this._entityIdField) { this.addIdToNewRow(newRow); } - newRow[this._entitySecondIdField as keyof T] = this.getNextFreeRowId() as T[keyof T]; + const nextId = this.getNextFreeRowId(); + newRow[this._entitySecondIdField as keyof T] = typeof newRow[this._entitySecondIdField as keyof T] === 'string' + ? String(nextId) as T[keyof T] + : nextId as T[keyof T]; this._newRows = [...this._newRows, { ...newRow }]; this.updateDiffQuery();