diff --git a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-team/manage-team.component.html b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-team/manage-team.component.html
index 2c814fc98a5..15b51047dd3 100644
--- a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-team/manage-team.component.html
+++ b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-team/manage-team.component.html
@@ -13,7 +13,12 @@
Students without a tea
Team {{ team.workgroupId }}
- 0 && !isUnassigned"
+ class="change-period"
+ href="#"
+ (click)="changePeriod($event)"
+ i18n
>Change Period
No students
@@ -39,7 +44,11 @@ Team {{ team.workgroupId }
(cdkDragExited)="dragExit($event)"
[cdkDragPreviewContainer]="'parent'"
>
-
+
diff --git a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-team/manage-team.component.spec.ts b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-team/manage-team.component.spec.ts
index d04a992952e..a3614cd02b5 100644
--- a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-team/manage-team.component.spec.ts
+++ b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-team/manage-team.component.spec.ts
@@ -1,75 +1,108 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MatCardModule } from '@angular/material/card';
-import { MatDialog } from '@angular/material/dialog';
+import { MatDialog, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { MatSnackBarModule } from '@angular/material/snack-bar';
-import { By } from '@angular/platform-browser';
import { UpdateWorkgroupService } from '../../../../../../app/services/updateWorkgroupService';
import { ConfigService } from '../../../../services/configService';
import { ManageTeamComponent } from './manage-team.component';
import { NO_ERRORS_SCHEMA } from '@angular/core';
+import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
+import { ManageTeamHarness } from './manage-team.harness';
+import { ManageStudentsModule } from '../manage-students.module';
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { of } from 'rxjs';
+import { RemoveUserConfirmDialogComponent } from '../remove-user-confirm-dialog/remove-user-confirm-dialog.component';
+import { HttpClient } from '@angular/common/http';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
-class ConfigServiceStub {
- getPermissions() {}
- retrieveConfig() {
- return {};
- }
-}
-
-class UpdateWorkgroupServiceStub {}
-
+let component: ManageTeamComponent;
let configService: ConfigService;
+let dialog: MatDialog;
let fixture: ComponentFixture;
-let component: ManageTeamComponent;
+let getPermissionsSpy: jasmine.Spy;
+let http: HttpClient;
+let manageTeamHarness: ManageTeamHarness;
+const studentName = 'a a';
+const studentUsername = 'aa0101';
describe('ManageTeamComponent', () => {
- beforeEach(() => {
+ beforeEach(async () => {
TestBed.configureTestingModule({
declarations: [ManageTeamComponent],
- imports: [MatSnackBarModule, MatCardModule],
- providers: [
- { provide: ConfigService, useClass: ConfigServiceStub },
- { provide: UpdateWorkgroupService, useClass: UpdateWorkgroupServiceStub },
- { provide: MatDialog, useValue: {} }
+ imports: [
+ BrowserAnimationsModule,
+ HttpClientTestingModule,
+ ManageStudentsModule,
+ MatCardModule,
+ MatDialogModule,
+ MatSnackBarModule
],
+ providers: [ConfigService, UpdateWorkgroupService],
schemas: [NO_ERRORS_SCHEMA]
});
configService = TestBed.inject(ConfigService);
+ dialog = TestBed.inject(MatDialog);
fixture = TestBed.createComponent(ManageTeamComponent);
+ http = TestBed.inject(HttpClient);
+ getPermissionsSpy = spyOn(configService, 'getPermissions');
+ spyOn(configService, 'getRunId').and.returnValue(1);
+ spyOnCanGradeStudentWork(true);
component = fixture.componentInstance;
- component.team = { workgroupId: 3, users: [{ id: 1 }] };
+ component.team = {
+ workgroupId: 10,
+ users: [{ id: 1, name: studentName, username: studentUsername }]
+ };
+ manageTeamHarness = await TestbedHarnessEnvironment.harnessForFixture(
+ fixture,
+ ManageTeamHarness
+ );
});
- changePeriodLinkVisible();
+ changePeriodLinkVisibility();
+ removeStudent();
});
-function changePeriodLinkVisible() {
+function spyOnCanGradeStudentWork(canGrade: boolean) {
+ getPermissionsSpy.and.returnValue({
+ canGradeStudentWork: canGrade,
+ canViewStudentNames: true,
+ canAuthorProject: true
+ });
+}
+
+function changePeriodLinkVisibility() {
describe('change period link', () => {
- it('should appear when user has GradeStudentWork permission', () => {
- spyOnCanGradeStudentWork(true);
- fixture.detectChanges();
- expect(getChangePeriodLink()).toBeTruthy();
+ describe('teacher has GradeStudentWork permission', () => {
+ it('makes change period link visible', async () => {
+ expect(await manageTeamHarness.isChangePeriodLinkVisible()).toBeTrue();
+ });
});
- it('should not appear when user does not have GradeStudentWork permission', () => {
- spyOnCanGradeStudentWork(false);
- fixture.detectChanges();
- expect(getChangePeriodLink()).toBeFalsy();
+ describe('teacher does not have GradeStudentWork permission', () => {
+ it('makes change period link not visible', async () => {
+ spyOnCanGradeStudentWork(false);
+ component.ngOnInit();
+ expect(await manageTeamHarness.isChangePeriodLinkVisible()).toBeFalse();
+ });
});
- it('should not appear when there are no members', () => {
- component.team.users = [];
- spyOnCanGradeStudentWork(true);
- fixture.detectChanges();
- expect(getChangePeriodLink()).toBeFalsy();
+ describe('team has no members', () => {
+ it('makes change period link not visible', async () => {
+ component.team.users = [];
+ expect(await manageTeamHarness.isChangePeriodLinkVisible()).toBeFalse();
+ });
});
});
}
-function spyOnCanGradeStudentWork(canGrade: boolean) {
- spyOn(configService, 'getPermissions').and.returnValue({
- canGradeStudentWork: canGrade,
- canViewStudentNames: true,
- canAuthorProject: true
+function removeStudent() {
+ describe('removeStudent()', () => {
+ describe('click remove student button on a student', () => {
+ it('removes student from the team', async () => {
+ spyOn(dialog, 'open').and.returnValue({
+ afterClosed: () => of(true)
+ } as MatDialogRef);
+ spyOn(http, 'delete').and.returnValue(of({}));
+ await manageTeamHarness.clickRemoveUser(`${studentName} (${studentUsername})`);
+ expect(await manageTeamHarness.getMemberCount()).toBe(0);
+ });
+ });
});
}
-
-function getChangePeriodLink() {
- return fixture.debugElement.query(By.css('.change-period'));
-}
diff --git a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-team/manage-team.component.ts b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-team/manage-team.component.ts
index 74230f4ecff..8065c646db9 100644
--- a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-team/manage-team.component.ts
+++ b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-team/manage-team.component.ts
@@ -22,7 +22,7 @@ import { getAvatarColorForWorkgroupId } from '../../../../common/workgroup/workg
})
export class ManageTeamComponent {
avatarColor: string;
- canChangePeriod: boolean;
+ canGradeStudentWork: boolean;
isUnassigned: boolean;
@Input() team: any;
@@ -35,11 +35,8 @@ export class ManageTeamComponent {
ngOnInit() {
this.avatarColor = getAvatarColorForWorkgroupId(this.team.workgroupId);
+ this.canGradeStudentWork = this.configService.getPermissions().canGradeStudentWork;
this.isUnassigned = this.team.workgroupId == null;
- this.canChangePeriod =
- this.configService.getPermissions().canGradeStudentWork &&
- this.team.users.length > 0 &&
- !this.isUnassigned;
}
changePeriod(event: Event) {
@@ -110,4 +107,8 @@ export class ManageTeamComponent {
}
});
}
+
+ protected removeUser(user: any): void {
+ this.team.users.splice(this.team.users.indexOf(user), 1);
+ }
}
diff --git a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-team/manage-team.harness.ts b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-team/manage-team.harness.ts
new file mode 100644
index 00000000000..923c97450c4
--- /dev/null
+++ b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-team/manage-team.harness.ts
@@ -0,0 +1,30 @@
+import { ComponentHarness } from '@angular/cdk/testing';
+import { ManageUserHarness } from '../manage-user/manage-user.harness';
+
+export class ManageTeamHarness extends ComponentHarness {
+ static hostSelector = 'manage-team';
+ protected getChangePeriodLink = this.locatorForOptional('.change-period');
+ protected getMembers = this.locatorForAll(ManageUserHarness);
+
+ async isChangePeriodLinkVisible(): Promise {
+ return (await this.getChangePeriodLink()) != null;
+ }
+
+ async getMember(username: string): Promise {
+ for (const member of await this.getMembers()) {
+ if ((await member.getUsername()) === username) {
+ return member;
+ }
+ }
+ return null;
+ }
+
+ async clickRemoveUser(username: string): Promise {
+ const member = await this.getMember(username);
+ await member.clickRemoveUserButton();
+ }
+
+ async getMemberCount(): Promise {
+ return (await this.getMembers()).length;
+ }
+}
diff --git a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-user/manage-user.component.html b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-user/manage-user.component.html
index ba07492efc9..5db862850d0 100644
--- a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-user/manage-user.component.html
+++ b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-user/manage-user.component.html
@@ -38,6 +38,8 @@
matTooltip="Remove student"
i18n-matTooltip
matTooltipPosition="above"
+ aria-label="Remove student"
+ i18n-aria-label
(click)="removeUser($event)"
>
clear
diff --git a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-user/manage-user.component.ts b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-user/manage-user.component.ts
index d87e1af4bc6..c8141a4f7d0 100644
--- a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-user/manage-user.component.ts
+++ b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-user/manage-user.component.ts
@@ -1,5 +1,5 @@
import { HttpClient } from '@angular/common/http';
-import { Component, Input, ViewEncapsulation } from '@angular/core';
+import { Component, EventEmitter, Input, Output, ViewEncapsulation } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { ConfigService } from '../../../../services/configService';
@@ -15,6 +15,7 @@ import { RemoveUserConfirmDialogComponent } from '../remove-user-confirm-dialog/
})
export class ManageUserComponent {
@Input() user: any;
+ @Output() removeUserEvent: EventEmitter = new EventEmitter();
constructor(
private dialog: MatDialog,
@@ -49,9 +50,17 @@ export class ManageUserComponent {
performRemoveUser() {
const runId = this.configService.getRunId();
const studentId = this.user.id;
- this.http.delete(`/api/teacher/run/${runId}/student/${studentId}/remove`).subscribe(() => {
- this.snackBar.open($localize`Removed ${this.user.name} (${this.user.username}) from unit.`);
- this.configService.retrieveConfig(`/api/config/classroomMonitor/${runId}`);
+ this.http.delete(`/api/teacher/run/${runId}/student/${studentId}/remove`).subscribe({
+ next: () => {
+ this.removeUserEvent.emit(this.user);
+ this.snackBar.open($localize`Removed ${this.user.name} (${this.user.username}) from unit.`);
+ this.configService.retrieveConfig(`/api/config/classroomMonitor/${runId}`);
+ },
+ error: () => {
+ this.snackBar.open(
+ $localize`Error: Could not remove ${this.user.name} (${this.user.username}) from unit.`
+ );
+ }
});
}
diff --git a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-user/manage-user.harness.ts b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-user/manage-user.harness.ts
new file mode 100644
index 00000000000..31ed4d2036a
--- /dev/null
+++ b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-user/manage-user.harness.ts
@@ -0,0 +1,19 @@
+import { ComponentHarness } from '@angular/cdk/testing';
+import { MatButtonHarness } from '@angular/material/button/testing';
+import { ShowStudentInfoHarness } from '../show-student-info/show-student-info.harness';
+
+export class ManageUserHarness extends ComponentHarness {
+ static hostSelector = 'manage-user';
+ protected getStudentInfo = this.locatorForOptional(ShowStudentInfoHarness);
+ protected getRemoveUserButton = this.locatorFor(
+ MatButtonHarness.with({ selector: '[aria-label="Remove student"]' })
+ );
+
+ async clickRemoveUserButton(): Promise {
+ (await this.getRemoveUserButton()).click();
+ }
+
+ async getUsername(): Promise {
+ return await (await this.getStudentInfo()).getUsernameText();
+ }
+}
diff --git a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/show-student-info/show-student-info.harness.ts b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/show-student-info/show-student-info.harness.ts
new file mode 100644
index 00000000000..eaeee710e28
--- /dev/null
+++ b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/show-student-info/show-student-info.harness.ts
@@ -0,0 +1,10 @@
+import { ComponentHarness } from '@angular/cdk/testing';
+
+export class ShowStudentInfoHarness extends ComponentHarness {
+ static hostSelector = 'show-student-info';
+ protected getUsername = this.locatorFor('.username');
+
+ async getUsernameText(): Promise {
+ return (await this.getUsername()).text();
+ }
+}
diff --git a/src/messages.xlf b/src/messages.xlf
index aa83700b406..0acec0acd95 100644
--- a/src/messages.xlf
+++ b/src/messages.xlf
@@ -12891,7 +12891,7 @@ Click "Cancel" to keep the invalid JSON open so you can fix it.
src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-team/manage-team.component.html
- 17
+ 22
@@ -12987,21 +12987,21 @@ Click "Cancel" to keep the invalid JSON open so you can fix it.No students
src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-team/manage-team.component.html
- 19
+ 24
src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-team/manage-team.component.ts
- 106
+ 103
src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-team/manage-team.component.ts
- 109
+ 106
@@ -13031,12 +13031,23 @@ Click "Cancel" to keep the invalid JSON open so you can fix it.src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-user/manage-user.component.html
38
+
+ src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-user/manage-user.component.html
+ 41
+
src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-user/manage-user.component.ts
- 53
+ 56
+
+
+
+
+
+ src/assets/wise5/classroomMonitor/classroomMonitorComponents/manageStudents/manage-user/manage-user.component.ts
+ 61