@@ -12,6 +12,7 @@ import { BehaviorSubject, of, throwError } from 'rxjs';
1212import { anything , instance , mock , verify , when } from 'ts-mockito' ;
1313import { ActivatedProjectService } from 'xforge-common/activated-project.service' ;
1414import { AuthService } from 'xforge-common/auth.service' ;
15+ import { CommandError , CommandErrorCode } from 'xforge-common/command.service' ;
1516import { FileService } from 'xforge-common/file.service' ;
1617import { I18nService } from 'xforge-common/i18n.service' ;
1718import { FileType } from 'xforge-common/models/file-offline-data' ;
@@ -308,6 +309,120 @@ describe('ServalProjectComponent', () => {
308309 verify ( mockSFProjectService . onlineSetServalConfig ( env . mockProjectId , anything ( ) ) ) . never ( ) ;
309310 expect ( env . statusDone ( env . servalConfigStatus ) ) . toBeNull ( ) ;
310311 } ) ) ;
312+
313+ it ( 'should notify of a backend error' , fakeAsync ( ( ) => {
314+ const env = new TestEnvironment ( ) ;
315+ when ( mockSFProjectService . onlineSetServalConfig ( env . mockProjectId , anything ( ) ) ) . thenReject (
316+ new CommandError ( CommandErrorCode . InternalError , 'error' )
317+ ) ;
318+ expect ( env . servalConfigTextArea . value ) . toBe ( '' ) ;
319+ expect ( env . statusError ( env . servalConfigStatus ) ) . toBeNull ( ) ;
320+
321+ env . setServalConfigValue ( '{}' ) ;
322+ env . clickElement ( env . saveServalConfigButton ) ;
323+
324+ verify ( mockSFProjectService . onlineSetServalConfig ( env . mockProjectId , anything ( ) ) ) . once ( ) ;
325+ expect ( env . statusError ( env . servalConfigStatus ) ) . not . toBeNull ( ) ;
326+ } ) ) ;
327+ } ) ;
328+
329+ describe ( 'quality estimation configuration' , ( ) => {
330+ it ( 'should change quality estimation config value' , fakeAsync ( ( ) => {
331+ const env = new TestEnvironment ( ) ;
332+ expect ( env . qualityEstimationConfigTextArea . value ) . toBe ( '' ) ;
333+ expect ( env . statusDone ( env . qualityEstimationConfigStatus ) ) . toBeNull ( ) ;
334+
335+ env . setQualityEstimationConfigValue ( '{ "version": "0.1", "slope": 109.6145, "intercept": -14.0633 }' ) ;
336+ env . clickElement ( env . saveQualityEstimationConfigButton ) ;
337+
338+ verify ( mockSFProjectService . onlineSetQualityEstimationConfig ( env . mockProjectId , anything ( ) ) ) . once ( ) ;
339+ expect ( env . statusDone ( env . qualityEstimationConfigStatus ) ) . not . toBeNull ( ) ;
340+ } ) ) ;
341+
342+ it ( 'should clear the quality estimation config value' , fakeAsync ( ( ) => {
343+ const env = new TestEnvironment ( {
344+ preTranslate : true ,
345+ draftConfig : { qualityEstimationConfig : { version : '0.1' , slope : 109.6145 , intercept : - 14.0633 } }
346+ } ) ;
347+ expect ( env . qualityEstimationConfigTextArea . value ) . toBe (
348+ '{"version":"0.1","slope":109.6145,"intercept":-14.0633}'
349+ ) ;
350+ expect ( env . statusDone ( env . qualityEstimationConfigStatus ) ) . toBeNull ( ) ;
351+
352+ env . setQualityEstimationConfigValue ( '' ) ;
353+ env . clickElement ( env . saveQualityEstimationConfigButton ) ;
354+
355+ verify ( mockSFProjectService . onlineSetQualityEstimationConfig ( env . mockProjectId , anything ( ) ) ) . once ( ) ;
356+ expect ( env . statusDone ( env . qualityEstimationConfigStatus ) ) . not . toBeNull ( ) ;
357+ } ) ) ;
358+
359+ it ( 'should not update an unchanged quality estimation config value' , fakeAsync ( ( ) => {
360+ const env = new TestEnvironment ( {
361+ preTranslate : true ,
362+ draftConfig : { qualityEstimationConfig : { version : '0.1' , slope : 109.6145 , intercept : - 14.0633 } }
363+ } ) ;
364+ expect ( env . qualityEstimationConfigTextArea . value ) . toBe (
365+ '{"version":"0.1","slope":109.6145,"intercept":-14.0633}'
366+ ) ;
367+ expect ( env . statusDone ( env . qualityEstimationConfigStatus ) ) . toBeNull ( ) ;
368+
369+ env . setQualityEstimationConfigValue ( '{ "version": "0.1", "slope": 109.6145, "intercept": -14.0633 }' ) ;
370+ env . clickElement ( env . saveQualityEstimationConfigButton ) ;
371+
372+ verify ( mockSFProjectService . onlineSetQualityEstimationConfig ( env . mockProjectId , anything ( ) ) ) . never ( ) ;
373+ expect ( env . statusDone ( env . qualityEstimationConfigStatus ) ) . toBeNull ( ) ;
374+ } ) ) ;
375+
376+ it ( 'should not update an unchanged empty quality estimation config value' , fakeAsync ( ( ) => {
377+ const env = new TestEnvironment ( ) ;
378+ expect ( env . qualityEstimationConfigTextArea . value ) . toBe ( '' ) ;
379+ expect ( env . statusDone ( env . qualityEstimationConfigStatus ) ) . toBeNull ( ) ;
380+
381+ env . setQualityEstimationConfigValue ( '' ) ;
382+ env . clickElement ( env . saveQualityEstimationConfigButton ) ;
383+
384+ verify ( mockSFProjectService . onlineSetQualityEstimationConfig ( env . mockProjectId , anything ( ) ) ) . never ( ) ;
385+ expect ( env . statusDone ( env . qualityEstimationConfigStatus ) ) . toBeNull ( ) ;
386+ } ) ) ;
387+
388+ it ( 'should not update a non-JSON value' , fakeAsync ( ( ) => {
389+ const env = new TestEnvironment ( ) ;
390+ expect ( env . qualityEstimationConfigTextArea . value ) . toBe ( '' ) ;
391+ expect ( env . statusError ( env . qualityEstimationConfigStatus ) ) . toBeNull ( ) ;
392+
393+ env . setQualityEstimationConfigValue ( 'test' ) ;
394+ env . clickElement ( env . saveQualityEstimationConfigButton ) ;
395+
396+ verify ( mockSFProjectService . onlineSetQualityEstimationConfig ( env . mockProjectId , anything ( ) ) ) . never ( ) ;
397+ expect ( env . statusError ( env . qualityEstimationConfigStatus ) ) . not . toBeNull ( ) ;
398+ } ) ) ;
399+
400+ it ( 'should not update an invalid value' , fakeAsync ( ( ) => {
401+ const env = new TestEnvironment ( ) ;
402+ expect ( env . qualityEstimationConfigTextArea . value ) . toBe ( '' ) ;
403+ expect ( env . statusError ( env . qualityEstimationConfigStatus ) ) . toBeNull ( ) ;
404+
405+ env . setQualityEstimationConfigValue ( '{"prop": "value"}' ) ;
406+ env . clickElement ( env . saveQualityEstimationConfigButton ) ;
407+
408+ verify ( mockSFProjectService . onlineSetQualityEstimationConfig ( env . mockProjectId , anything ( ) ) ) . never ( ) ;
409+ expect ( env . statusError ( env . qualityEstimationConfigStatus ) ) . not . toBeNull ( ) ;
410+ } ) ) ;
411+
412+ it ( 'should notify of a backend error' , fakeAsync ( ( ) => {
413+ const env = new TestEnvironment ( ) ;
414+ when ( mockSFProjectService . onlineSetQualityEstimationConfig ( env . mockProjectId , anything ( ) ) ) . thenReject (
415+ new CommandError ( CommandErrorCode . InternalError , 'error' )
416+ ) ;
417+ expect ( env . qualityEstimationConfigTextArea . value ) . toBe ( '' ) ;
418+ expect ( env . statusError ( env . qualityEstimationConfigStatus ) ) . toBeNull ( ) ;
419+
420+ env . setQualityEstimationConfigValue ( '{ "version": "0.1", "slope": 109.6145, "intercept": -14.0633 }' ) ;
421+ env . clickElement ( env . saveQualityEstimationConfigButton ) ;
422+
423+ verify ( mockSFProjectService . onlineSetQualityEstimationConfig ( env . mockProjectId , anything ( ) ) ) . once ( ) ;
424+ expect ( env . statusError ( env . qualityEstimationConfigStatus ) ) . not . toBeNull ( ) ;
425+ } ) ) ;
311426 } ) ;
312427 } ) ;
313428
@@ -363,7 +478,8 @@ describe('ServalProjectComponent', () => {
363478 lastSelectedTrainingScriptureRanges : args . draftConfig ?. lastSelectedTrainingScriptureRanges ?? undefined ,
364479 lastSelectedTranslationScriptureRanges :
365480 args . draftConfig ?. lastSelectedTranslationScriptureRanges ?? undefined ,
366- servalConfig : args . draftConfig ?. servalConfig ?? undefined
481+ servalConfig : args . draftConfig ?. servalConfig ?? undefined ,
482+ qualityEstimationConfig : args . draftConfig ?. qualityEstimationConfig ?? undefined
367483 } ,
368484 preTranslate : args . preTranslate ,
369485 source : {
@@ -395,6 +511,7 @@ describe('ServalProjectComponent', () => {
395511 when ( mockDraftGenerationService . getBuildProgress ( anything ( ) ) ) . thenReturn ( of ( { additionalInfo : { } } as BuildDto ) ) ;
396512 when ( mockSFProjectService . hasDraft ( anything ( ) ) ) . thenReturn ( args . preTranslate ) ;
397513 when ( mockSFProjectService . onlineSetServalConfig ( this . mockProjectId , anything ( ) ) ) . thenResolve ( ) ;
514+ when ( mockSFProjectService . onlineSetQualityEstimationConfig ( this . mockProjectId , anything ( ) ) ) . thenResolve ( ) ;
398515 const trainingData : TrainingDataDoc [ ] = [
399516 {
400517 id : 'training01' ,
@@ -444,6 +561,18 @@ describe('ServalProjectComponent', () => {
444561 return this . fixture . nativeElement . querySelector ( '.training-data-table td button' ) ;
445562 }
446563
564+ get qualityEstimationConfigStatus ( ) : DebugElement {
565+ return this . fixture . debugElement . query ( By . css ( '#quality-estimation-config-status' ) ) ;
566+ }
567+
568+ get qualityEstimationConfigTextArea ( ) : HTMLTextAreaElement {
569+ return this . fixture . nativeElement . querySelector ( '#quality-estimation-config' ) as HTMLTextAreaElement ;
570+ }
571+
572+ get saveQualityEstimationConfigButton ( ) : HTMLInputElement {
573+ return this . fixture . nativeElement . querySelector ( '#save-quality-estimation-config' ) ;
574+ }
575+
447576 get saveServalConfigButton ( ) : HTMLInputElement {
448577 return this . fixture . nativeElement . querySelector ( '#save-serval-config' ) ;
449578 }
@@ -485,6 +614,14 @@ describe('ServalProjectComponent', () => {
485614 return node . querySelector ( '.translation-range' ) ?. textContent ?? '' ;
486615 }
487616
617+ setQualityEstimationConfigValue ( value : string ) : void {
618+ this . qualityEstimationConfigTextArea . value = value ;
619+ this . qualityEstimationConfigTextArea . dispatchEvent ( new Event ( 'input' ) ) ;
620+ this . fixture . detectChanges ( ) ;
621+ tick ( ) ;
622+ this . fixture . detectChanges ( ) ;
623+ }
624+
488625 setServalConfigValue ( value : string ) : void {
489626 this . servalConfigTextArea . value = value ;
490627 this . servalConfigTextArea . dispatchEvent ( new Event ( 'input' ) ) ;
@@ -496,5 +633,9 @@ describe('ServalProjectComponent', () => {
496633 statusDone ( element : DebugElement ) : HTMLElement {
497634 return element . nativeElement . querySelector ( '.check-icon' ) as HTMLElement ;
498635 }
636+
637+ statusError ( element : DebugElement ) : HTMLElement {
638+ return element . nativeElement . querySelector ( '.error-icon' ) as HTMLElement ;
639+ }
499640 }
500641} ) ;
0 commit comments