diff --git a/src/assets/wise5/authoringTool/peer-grouping/author-peer-grouping-dialog/author-peer-grouping-dialog.component.ts b/src/assets/wise5/authoringTool/peer-grouping/author-peer-grouping-dialog/author-peer-grouping-dialog.component.ts index a99debed097..6912ee730b0 100644 --- a/src/assets/wise5/authoringTool/peer-grouping/author-peer-grouping-dialog/author-peer-grouping-dialog.component.ts +++ b/src/assets/wise5/authoringTool/peer-grouping/author-peer-grouping-dialog/author-peer-grouping-dialog.component.ts @@ -4,6 +4,7 @@ import { PeerGrouping } from '../../../../../app/domain/peerGrouping'; import { ReferenceComponent } from '../../../../../app/domain/referenceComponent'; import { ProjectService } from '../../../services/projectService'; import { AVAILABLE_LOGIC, AVAILABLE_MODES, PeerGroupingLogic } from '../PeerGroupingLogic'; +import { MatSnackBar } from '@angular/material/snack-bar'; @Directive() export abstract class AuthorPeerGroupingDialogComponent implements OnInit { @@ -18,7 +19,8 @@ export abstract class AuthorPeerGroupingDialogComponent implements OnInit { constructor( protected dialogRef: MatDialogRef, - protected projectService: ProjectService + protected projectService: ProjectService, + protected snackBar: MatSnackBar ) { this.availableLogic = AVAILABLE_LOGIC; } @@ -52,4 +54,15 @@ export abstract class AuthorPeerGroupingDialogComponent implements OnInit { cancel(): void { this.dialogRef.close(); } + + protected handleError(error: any): void { + switch (error.messageCode) { + case 'genericError': + this.snackBar.open($localize`An error occurred. Please try again.`); + break; + case 'notAuthorized': + this.snackBar.open($localize`You are not allowed to perform this action.`); + break; + } + } } diff --git a/src/assets/wise5/authoringTool/peer-grouping/create-new-peer-grouping-dialog/create-new-peer-grouping-dialog.component.spec.ts b/src/assets/wise5/authoringTool/peer-grouping/create-new-peer-grouping-dialog/create-new-peer-grouping-dialog.component.spec.ts index f9ea8a08a7a..e50bc501421 100644 --- a/src/assets/wise5/authoringTool/peer-grouping/create-new-peer-grouping-dialog/create-new-peer-grouping-dialog.component.spec.ts +++ b/src/assets/wise5/authoringTool/peer-grouping/create-new-peer-grouping-dialog/create-new-peer-grouping-dialog.component.spec.ts @@ -1,7 +1,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatDialogRef } from '@angular/material/dialog'; -import { MatSnackBarModule } from '@angular/material/snack-bar'; -import { of } from 'rxjs'; +import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar'; +import { of, throwError } from 'rxjs'; import { PeerGrouping } from '../../../../../app/domain/peerGrouping'; import { ReferenceComponent } from '../../../../../app/domain/referenceComponent'; import { StudentTeacherCommonServicesModule } from '../../../../../app/student-teacher-common-services.module'; @@ -13,8 +13,10 @@ const TAG1: string = 'tag1'; const REFERENCE_COMPONENT_NODE_ID1 = 'node1'; const REFERENCE_COMPONENT_COMPONENT_ID1 = 'component1'; let component: CreateNewPeerGroupingDialogComponent; -let createNewPeerGroupingSpy: jasmine.Spy, dialogCloseSpy: jasmine.Spy; +let createNewPeerGroupingSpy: jasmine.Spy; +let dialogCloseSpy: jasmine.Spy; let fixture: ComponentFixture; +let snackBar: MatSnackBar; describe('CreateNewPeerGroupingDialogComponent', () => { beforeEach(async () => { @@ -30,6 +32,7 @@ describe('CreateNewPeerGroupingDialogComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(CreateNewPeerGroupingDialogComponent); component = fixture.componentInstance; + snackBar = TestBed.inject(MatSnackBar); fixture.detectChanges(); }); create(); @@ -41,6 +44,7 @@ function create() { create_DifferentIdeasMaximizeLogic_ShouldCreatePeerGroup(); create_DifferentScoresAnyLogic_ShouldCreatePeerGroup(); create_DifferentScoresMaximizeLogic_ShouldCreatePeerGroup(); + create_ErrorOccurs_ShowsError(); } function create_RandomLogic_ShouldCreatePeerGroup() { @@ -98,3 +102,41 @@ function expectLogicCreateNewPeerGrouping(logicType: string, mode: string) { expect(createNewPeerGroupingSpy).toHaveBeenCalledWith(newPeerGrouping); expect(dialogCloseSpy).toHaveBeenCalled(); } + +function create_ErrorOccurs_ShowsError(): void { + describe('create new peer grouping returns error', () => { + create_GenericErrorOccurs_ShowsError(); + create_NotAuthorizedErrorOccurs_ShowsError(); + }); +} + +function create_GenericErrorOccurs_ShowsError(): void { + describe('returns generic error', () => { + it('shows generic error message in snackbar', async () => { + returnErrorExpectErrorMessage('genericError', 'An error occurred. Please try again.'); + }); + }); +} + +function create_NotAuthorizedErrorOccurs_ShowsError(): void { + describe('returns not authorized error', () => { + it('shows not authorized error in snackbar', async () => { + returnErrorExpectErrorMessage('notAuthorized', 'You are not allowed to perform this action.'); + }); + }); +} + +function returnErrorExpectErrorMessage(messageCode: string, errorMessage: string): void { + const snackBarSpy = spyOn(snackBar, 'open'); + createNewPeerGroupingSpy.and.returnValue( + throwError(() => { + return { + error: { + messageCode: messageCode + } + }; + }) + ); + component.create(); + expect(snackBarSpy).toHaveBeenCalledWith(errorMessage); +} diff --git a/src/assets/wise5/authoringTool/peer-grouping/create-new-peer-grouping-dialog/create-new-peer-grouping-dialog.component.ts b/src/assets/wise5/authoringTool/peer-grouping/create-new-peer-grouping-dialog/create-new-peer-grouping-dialog.component.ts index 5941ce34f45..84fa53ea854 100644 --- a/src/assets/wise5/authoringTool/peer-grouping/create-new-peer-grouping-dialog/create-new-peer-grouping-dialog.component.ts +++ b/src/assets/wise5/authoringTool/peer-grouping/create-new-peer-grouping-dialog/create-new-peer-grouping-dialog.component.ts @@ -17,9 +17,9 @@ export class CreateNewPeerGroupingDialogComponent extends AuthorPeerGroupingDial protected dialogRef: MatDialogRef, private peerGroupingAuthoringService: PeerGroupingAuthoringService, protected projectService: ProjectService, - private snackBar: MatSnackBar + protected snackBar: MatSnackBar ) { - super(dialogRef, projectService); + super(dialogRef, projectService, snackBar); } ngOnInit(): void { @@ -29,13 +29,13 @@ export class CreateNewPeerGroupingDialogComponent extends AuthorPeerGroupingDial create(): Subscription { this.peerGrouping.tag = this.peerGroupingAuthoringService.getUniqueTag(); this.updatePeerGroupingLogic(); - return this.peerGroupingAuthoringService.createNewPeerGrouping(this.peerGrouping).subscribe( - () => { + return this.peerGroupingAuthoringService.createNewPeerGrouping(this.peerGrouping).subscribe({ + next: () => { this.dialogRef.close(); }, - () => { - this.snackBar.open($localize`Please try again (Error: duplicate tag).`); + error: ({ error }) => { + this.handleError(error); } - ); + }); } } diff --git a/src/assets/wise5/authoringTool/peer-grouping/edit-peer-grouping-dialog/edit-peer-grouping-dialog.component.spec.ts b/src/assets/wise5/authoringTool/peer-grouping/edit-peer-grouping-dialog/edit-peer-grouping-dialog.component.spec.ts index d24ffc03911..e25bed06350 100644 --- a/src/assets/wise5/authoringTool/peer-grouping/edit-peer-grouping-dialog/edit-peer-grouping-dialog.component.spec.ts +++ b/src/assets/wise5/authoringTool/peer-grouping/edit-peer-grouping-dialog/edit-peer-grouping-dialog.component.spec.ts @@ -1,5 +1,5 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { of } from 'rxjs'; +import { of, throwError } from 'rxjs'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { PeerGroupingAuthoringService } from '../../../services/peerGroupingAuthoringService'; import { PeerGroupingTestingModule } from '../peer-grouping-testing.module'; @@ -7,19 +7,23 @@ import { EditPeerGroupingDialogComponent } from './edit-peer-grouping-dialog.com import { PeerGrouping } from '../../../../../app/domain/peerGrouping'; import { StudentTeacherCommonServicesModule } from '../../../../../app/student-teacher-common-services.module'; import { DIFFERENT_IDEAS_VALUE, DIFFERENT_SCORES_VALUE } from '../PeerGroupingLogic'; +import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar'; let component: EditPeerGroupingDialogComponent; const componentId1 = 'component1'; let dialogCloseSpy: jasmine.Spy; let fixture: ComponentFixture; const modeAny: string = 'any'; -const modeMaximize: string = 'maximize'; const nodeId1 = 'node1'; +const modeMaximize: string = 'maximize'; +let snackBar: MatSnackBar; +let peerGroupingAuthoringService; +let updatePeerGroupingSpy: jasmine.Spy; describe('EditPeerGroupingDialogComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [PeerGroupingTestingModule, StudentTeacherCommonServicesModule], + imports: [MatSnackBarModule, PeerGroupingTestingModule, StudentTeacherCommonServicesModule], declarations: [EditPeerGroupingDialogComponent], providers: [ { @@ -36,7 +40,10 @@ describe('EditPeerGroupingDialogComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(EditPeerGroupingDialogComponent); component = fixture.componentInstance; + peerGroupingAuthoringService = TestBed.inject(PeerGroupingAuthoringService); + updatePeerGroupingSpy = spyOn(peerGroupingAuthoringService, 'updatePeerGrouping'); dialogCloseSpy = spyOn(TestBed.inject(MatDialogRef), 'close'); + snackBar = TestBed.inject(MatSnackBar); fixture.detectChanges(); }); @@ -46,56 +53,86 @@ describe('EditPeerGroupingDialogComponent', () => { }); function savePeerGrouping() { - it('should save peer grouping', async () => { - const settings = new PeerGrouping(); - component.peerGrouping = settings; - const updatePeerGroupingSpy = spyOn( - TestBed.inject(PeerGroupingAuthoringService), - 'updatePeerGrouping' - ).and.returnValue(of(settings)); - component.save(); - expect(updatePeerGroupingSpy).toHaveBeenCalledWith(settings); - expect(dialogCloseSpy).toHaveBeenCalled(); - }); + describe('save is clicked', () => { + describe('save to backend is successful', () => { + it('closes the dialog', async () => { + const settings = new PeerGrouping(); + component.peerGrouping = settings; + updatePeerGroupingSpy.and.returnValue(of(settings)); + component.save(); + expect(updatePeerGroupingSpy).toHaveBeenCalledWith(settings); + expect(dialogCloseSpy).toHaveBeenCalled(); + }); + }); - it('should save peer grouping with random logic', () => { - savePeerGroupingWithLogic('random', null, 'random'); - }); + describe('peer grouping logic is random', () => { + it('properly generates the random logic string', () => { + savePeerGroupingWithLogic('random', null, 'random'); + }); + }); - it('should save peer grouping with manual logic', () => { - savePeerGroupingWithLogic('manual', null, 'manual'); - }); + describe('peer grouping logic is manual', () => { + it('properly generates the manual logic string', () => { + savePeerGroupingWithLogic('manual', null, 'manual'); + }); + }); - it('should save peer grouping with different ideas any logic', () => { - savePeerGroupingWithLogic( - DIFFERENT_IDEAS_VALUE, - modeAny, - `${DIFFERENT_IDEAS_VALUE}("${nodeId1}", "${componentId1}", "${modeAny}")` - ); - }); + describe('peer grouping logic is different ideas', () => { + it('properly generates the different ideas logic string', () => { + savePeerGroupingWithLogic( + DIFFERENT_IDEAS_VALUE, + modeAny, + `${DIFFERENT_IDEAS_VALUE}("${nodeId1}", "${componentId1}", "${modeAny}")` + ); + }); + }); - it('should save peer grouping with different ideas maximize logic', () => { - savePeerGroupingWithLogic( - DIFFERENT_IDEAS_VALUE, - modeMaximize, - `${DIFFERENT_IDEAS_VALUE}("${nodeId1}", "${componentId1}", "${modeMaximize}")` - ); - }); + describe('peer grouping logic is different ideas maximize logic', () => { + it('properly generates the different ideas maximize logic string', () => { + savePeerGroupingWithLogic( + DIFFERENT_IDEAS_VALUE, + modeMaximize, + `${DIFFERENT_IDEAS_VALUE}("${nodeId1}", "${componentId1}", "${modeMaximize}")` + ); + }); + }); - it('should save peer grouping with different scores any logic', () => { - savePeerGroupingWithLogic( - DIFFERENT_SCORES_VALUE, - modeAny, - `${DIFFERENT_SCORES_VALUE}("${nodeId1}", "${componentId1}", "${modeAny}")` - ); - }); + describe('peer grouping logic is different scores', () => { + it('properly generates the different scores logic string', () => { + savePeerGroupingWithLogic( + DIFFERENT_SCORES_VALUE, + modeAny, + `${DIFFERENT_SCORES_VALUE}("${nodeId1}", "${componentId1}", "${modeAny}")` + ); + }); + }); + + describe('peer grouping logic is different scores maximize logic', () => { + it('proplery generates the different scores maximize logic string', () => { + savePeerGroupingWithLogic( + DIFFERENT_SCORES_VALUE, + modeMaximize, + `${DIFFERENT_SCORES_VALUE}("${nodeId1}", "${componentId1}", "${modeMaximize}")` + ); + }); + }); - it('should save peer grouping with different scores maximize logic', () => { - savePeerGroupingWithLogic( - DIFFERENT_SCORES_VALUE, - modeMaximize, - `${DIFFERENT_SCORES_VALUE}("${nodeId1}", "${componentId1}", "${modeMaximize}")` - ); + describe('save to backend returns not authorized error', () => { + it('shows not authorized error', () => { + const snackBarSpy = spyOn(snackBar, 'open'); + updatePeerGroupingSpy.and.returnValue( + throwError(() => { + return { + error: { + messageCode: 'notAuthorized' + } + }; + }) + ); + component.save(); + expect(snackBarSpy).toHaveBeenCalledWith('You are not allowed to perform this action.'); + }); + }); }); } @@ -108,24 +145,26 @@ function savePeerGroupingWithLogic(logicType: string, mode: string, expectedLogi componentId: 'component1' }; component.mode = mode; - spyOn(TestBed.inject(PeerGroupingAuthoringService), 'updatePeerGrouping').and.returnValue( - of(peerGrouping) - ); + updatePeerGroupingSpy.and.returnValue(of(peerGrouping)); component.save(); expect(component.peerGrouping.logic).toEqual(expectedLogic); } function deletePeerGrouping() { - it('should delete peer grouping', () => { - spyOn(window, 'confirm').and.returnValue(true); - component.delete(); - expect(dialogCloseSpy).toHaveBeenCalled(); + describe('delete is clicked', () => { + it('deletes peer grouping', () => { + spyOn(window, 'confirm').and.returnValue(true); + component.delete(); + expect(dialogCloseSpy).toHaveBeenCalled(); + }); }); } function cancelPeerGrouping() { - it('should cancel peer grouping', () => { - component.cancel(); - expect(dialogCloseSpy).toHaveBeenCalled(); + describe('cancel is clicked', () => { + it('cancels peer grouping', () => { + component.cancel(); + expect(dialogCloseSpy).toHaveBeenCalled(); + }); }); } diff --git a/src/assets/wise5/authoringTool/peer-grouping/edit-peer-grouping-dialog/edit-peer-grouping-dialog.component.ts b/src/assets/wise5/authoringTool/peer-grouping/edit-peer-grouping-dialog/edit-peer-grouping-dialog.component.ts index 743d1aab076..2fbe359cee0 100644 --- a/src/assets/wise5/authoringTool/peer-grouping/edit-peer-grouping-dialog/edit-peer-grouping-dialog.component.ts +++ b/src/assets/wise5/authoringTool/peer-grouping/edit-peer-grouping-dialog/edit-peer-grouping-dialog.component.ts @@ -10,6 +10,7 @@ import { DIFFERENT_SCORES_REGEX, DIFFERENT_SCORES_VALUE } from '../PeerGroupingLogic'; +import { MatSnackBar } from '@angular/material/snack-bar'; @Component({ selector: 'edit-peer-grouping-dialog', @@ -23,9 +24,10 @@ export class EditPeerGroupingDialogComponent extends AuthorPeerGroupingDialogCom @Inject(MAT_DIALOG_DATA) public peerGrouping: PeerGrouping, protected dialogRef: MatDialogRef, private peerGroupingAuthoringService: PeerGroupingAuthoringService, - protected projectService: ProjectService + protected projectService: ProjectService, + protected snackBar: MatSnackBar ) { - super(dialogRef, projectService); + super(dialogRef, projectService, snackBar); } ngOnInit(): void { @@ -53,8 +55,13 @@ export class EditPeerGroupingDialogComponent extends AuthorPeerGroupingDialogCom save(): void { this.updatePeerGroupingLogic(); - this.peerGroupingAuthoringService.updatePeerGrouping(this.peerGrouping).subscribe(() => { - this.dialogRef.close(); + this.peerGroupingAuthoringService.updatePeerGrouping(this.peerGrouping).subscribe({ + next: () => { + this.dialogRef.close(); + }, + error: ({ error }) => { + this.handleError(error); + } }); } diff --git a/src/messages.xlf b/src/messages.xlf index 499b68ace8c..56850b8e587 100644 --- a/src/messages.xlf +++ b/src/messages.xlf @@ -1798,6 +1798,10 @@ Click "Cancel" to keep the invalid JSON open so you can fix it.src/app/forgot/teacher/forgot-teacher-password-change/forgot-teacher-password-change.component.ts 157 + + src/assets/wise5/authoringTool/peer-grouping/author-peer-grouping-dialog/author-peer-grouping-dialog.component.ts + 61 + Thank you for contacting WISE! @@ -11766,6 +11770,13 @@ Click "Cancel" to keep the invalid JSON open so you can fix it.22 + + You are not allowed to perform this action. + + src/assets/wise5/authoringTool/peer-grouping/author-peer-grouping-dialog/author-peer-grouping-dialog.component.ts + 64 + + Create New Peer Grouping @@ -11832,13 +11843,6 @@ Click "Cancel" to keep the invalid JSON open so you can fix it.63 - - Please try again (Error: duplicate tag). - - src/assets/wise5/authoringTool/peer-grouping/create-new-peer-grouping-dialog/create-new-peer-grouping-dialog.component.ts - 37 - - Edit Peer Grouping @@ -11878,7 +11882,7 @@ Click "Cancel" to keep the invalid JSON open so you can fix it.Are you sure you want to delete this Peer Grouping? src/assets/wise5/authoringTool/peer-grouping/edit-peer-grouping-dialog/edit-peer-grouping-dialog.component.ts - 62 + 69