({
id: '',
email: '',
@@ -83,6 +90,15 @@ describe('AdminHomePageComponent', () => {
component.instructorInstitution = 'Instructor Institution';
fixture.detectChanges();
+ const accountCreateRequest = accountCreateRequestBuilder
+ .instructorName('Instructor Name')
+ .instructorEmail('instructor@example.com')
+ .instructorInstitution('Instructor Institution')
+ .build();
+
+ const createAccountRequestSpy = jest.spyOn(accountService, 'createAccountRequest')
+ .mockReturnValue(of(accountRequestBuilder.build()));
+
const accountRequest = accountRequestBuilder
.name('Instructor Name')
.email('instructor@example.com')
@@ -94,14 +110,14 @@ describe('AdminHomePageComponent', () => {
],
};
- jest.spyOn(accountService, 'createAccountRequest')
- .mockReturnValue(of(accountRequest));
jest.spyOn(accountService, 'getPendingAccountRequests')
.mockReturnValue(of(accountRequests));
const button: any = fixture.debugElement.nativeElement.querySelector('#add-instructor');
button.click();
+ expect(createAccountRequestSpy).toHaveBeenCalledWith(accountCreateRequest);
+
// Clear instructor fields
expect(component.instructorName).toEqual('');
expect(component.instructorEmail).toEqual('');
@@ -115,7 +131,6 @@ describe('AdminHomePageComponent', () => {
it('validateAndAddInstructorDetail: should not add one instructor to list if some fields are empty', () => {
const button: any = fixture.debugElement.nativeElement.querySelector('#add-instructor');
- const createAccountRequestSpy = jest.spyOn(accountService, 'createAccountRequest');
component.instructorName = '';
component.instructorEmail = 'instructor@example.com';
@@ -124,6 +139,11 @@ describe('AdminHomePageComponent', () => {
button.click();
+ expect(component.instructorName).toEqual('');
+ expect(component.instructorEmail).toEqual('instructor@example.com');
+ expect(component.instructorInstitution).toEqual('Instructor Institution');
+ expect(component.accountReqs.length).toEqual(0);
+
component.instructorName = 'Instructor Name';
component.instructorEmail = '';
component.instructorInstitution = 'Instructor Institution';
@@ -131,6 +151,11 @@ describe('AdminHomePageComponent', () => {
button.click();
+ expect(component.instructorName).toEqual('Instructor Name');
+ expect(component.instructorEmail).toEqual('');
+ expect(component.instructorInstitution).toEqual('Instructor Institution');
+ expect(component.accountReqs.length).toEqual(0);
+
component.instructorName = 'Instructor Name';
component.instructorEmail = 'instructor@example.com';
component.instructorInstitution = '';
@@ -138,7 +163,10 @@ describe('AdminHomePageComponent', () => {
button.click();
- expect(createAccountRequestSpy).not.toHaveBeenCalled();
+ expect(component.instructorName).toEqual('Instructor Name');
+ expect(component.instructorEmail).toEqual('instructor@example.com');
+ expect(component.instructorInstitution).toEqual('');
+ expect(component.accountReqs.length).toEqual(0);
});
it('validateAndAddInstructorDetails: should only add valid instructor details in the single line field', () => {
@@ -151,6 +179,20 @@ describe('AdminHomePageComponent', () => {
].join('\n');
fixture.detectChanges();
+ const accountCreateRequestA = accountCreateRequestBuilder
+ .instructorName('Instructor A')
+ .instructorEmail('instructora@example.com')
+ .instructorInstitution('Institution A')
+ .build();
+ const accountCreateRequestD = accountCreateRequestBuilder
+ .instructorName('Instructor D')
+ .instructorEmail('instructord@example.com')
+ .instructorInstitution('Institution D')
+ .build();
+
+ const createAccountRequestSpy = jest.spyOn(accountService, 'createAccountRequest')
+ .mockReturnValue(of(accountRequestBuilder.build()));
+
const accountRequestA = accountRequestBuilder
.name('Instructor A')
.email('instructora@example.com')
@@ -168,9 +210,6 @@ describe('AdminHomePageComponent', () => {
],
};
- // We are not testing the value createAccountRequest is being called with so it can be any value
- jest.spyOn(accountService, 'createAccountRequest')
- .mockReturnValue(of(accountRequestA));
jest.spyOn(accountService, 'getPendingAccountRequests')
.mockReturnValue(of(accountRequests));
@@ -183,6 +222,9 @@ describe('AdminHomePageComponent', () => {
'| instructore@example.com | Institution E',
].join('\r\n'));
+ expect(createAccountRequestSpy).toHaveBeenNthCalledWith(1, accountCreateRequestA);
+ expect(createAccountRequestSpy).toHaveBeenNthCalledWith(2, accountCreateRequestD);
+
expect(component.accountReqs.length).toEqual(2);
expect(component.accountReqs[0].name).toEqual('Instructor A');
@@ -238,6 +280,20 @@ describe('AdminHomePageComponent', () => {
Instructor B \t instructorb@example.com \t Sample Institution B`;
fixture.detectChanges();
+ const accountCreateRequestA = accountCreateRequestBuilder
+ .instructorName('Instructor A')
+ .instructorEmail('instructora@example.com')
+ .instructorInstitution('Sample Institution A')
+ .build();
+ const accountCreateRequestB = accountCreateRequestBuilder
+ .instructorName('Instructor B')
+ .instructorEmail('instructorb@example.com')
+ .instructorInstitution('Sample Institution B')
+ .build();
+
+ const createAccountRequestSpy = jest.spyOn(accountService, 'createAccountRequest')
+ .mockReturnValue(of(accountRequestBuilder.build()));
+
const accountRequestA = accountRequestBuilder
.name('Instructor A')
.email('instructora@example.com')
@@ -255,8 +311,6 @@ describe('AdminHomePageComponent', () => {
],
};
- jest.spyOn(accountService, 'createAccountRequest')
- .mockReturnValue(of(accountRequestA));
jest.spyOn(accountService, 'getPendingAccountRequests')
.mockReturnValue(of(accountRequests));
@@ -264,6 +318,10 @@ describe('AdminHomePageComponent', () => {
button.click();
expect(component.instructorDetails).toEqual('');
+
+ expect(createAccountRequestSpy).toHaveBeenNthCalledWith(1, accountCreateRequestA);
+ expect(createAccountRequestSpy).toHaveBeenNthCalledWith(2, accountCreateRequestB);
+
expect(component.accountReqs.length).toEqual(2);
expect(component.accountReqs[0].name).toEqual('Instructor A');
@@ -281,6 +339,20 @@ describe('AdminHomePageComponent', () => {
Instructor B | instructorb@example.com | Sample Institution B`;
fixture.detectChanges();
+ const accountCreateRequestA = accountCreateRequestBuilder
+ .instructorName('Instructor A')
+ .instructorEmail('instructora@example.com')
+ .instructorInstitution('Sample Institution A')
+ .build();
+ const accountCreateRequestB = accountCreateRequestBuilder
+ .instructorName('Instructor B')
+ .instructorEmail('instructorb@example.com')
+ .instructorInstitution('Sample Institution B')
+ .build();
+
+ const createAccountRequestSpy = jest.spyOn(accountService, 'createAccountRequest')
+ .mockReturnValue(of(accountRequestBuilder.build()));
+
const accountRequestA = accountRequestBuilder
.name('Instructor A')
.email('instructora@example.com')
@@ -298,8 +370,6 @@ describe('AdminHomePageComponent', () => {
],
};
- jest.spyOn(accountService, 'createAccountRequest')
- .mockReturnValueOnce(of(accountRequestA));
jest.spyOn(accountService, 'getPendingAccountRequests')
.mockReturnValue(of(accountRequests));
@@ -307,6 +377,10 @@ describe('AdminHomePageComponent', () => {
button.click();
expect(component.instructorDetails).toEqual('');
+
+ expect(createAccountRequestSpy).toHaveBeenNthCalledWith(1, accountCreateRequestA);
+ expect(createAccountRequestSpy).toHaveBeenNthCalledWith(2, accountCreateRequestB);
+
expect(component.accountReqs.length).toEqual(2);
expect(component.accountReqs[0].name).toEqual('Instructor A');
From 63fb244db633e1b9dd2a872a1a72fef0fef97368 Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Mon, 3 Jun 2024 04:31:07 +1200
Subject: [PATCH 09/25] Add test for fetchAccountRequests
---
.../admin-home-page.component.spec.ts | 149 ++++++------------
1 file changed, 45 insertions(+), 104 deletions(-)
diff --git a/src/web/app/pages-admin/admin-home-page/admin-home-page.component.spec.ts b/src/web/app/pages-admin/admin-home-page/admin-home-page.component.spec.ts
index 53d3adca9a1..3afa0d5ccec 100644
--- a/src/web/app/pages-admin/admin-home-page/admin-home-page.component.spec.ts
+++ b/src/web/app/pages-admin/admin-home-page/admin-home-page.component.spec.ts
@@ -84,7 +84,7 @@ describe('AdminHomePageComponent', () => {
expect(component).toBeTruthy();
});
- it('validateAndAddInstructorDetail: should add one instructor to list if all fields are filled', () => {
+ it('validateAndAddInstructorDetail: should create one instructor account request if all fields are filled', () => {
component.instructorName = 'Instructor Name';
component.instructorEmail = 'instructor@example.com';
component.instructorInstitution = 'Instructor Institution';
@@ -99,38 +99,22 @@ describe('AdminHomePageComponent', () => {
const createAccountRequestSpy = jest.spyOn(accountService, 'createAccountRequest')
.mockReturnValue(of(accountRequestBuilder.build()));
- const accountRequest = accountRequestBuilder
- .name('Instructor Name')
- .email('instructor@example.com')
- .institute('Instructor Institution')
- .build();
- const accountRequests: AccountRequests = {
- accountRequests: [
- accountRequest,
- ],
- };
-
- jest.spyOn(accountService, 'getPendingAccountRequests')
- .mockReturnValue(of(accountRequests));
-
const button: any = fixture.debugElement.nativeElement.querySelector('#add-instructor');
button.click();
+ expect(createAccountRequestSpy).toHaveBeenCalledTimes(1);
expect(createAccountRequestSpy).toHaveBeenCalledWith(accountCreateRequest);
// Clear instructor fields
expect(component.instructorName).toEqual('');
expect(component.instructorEmail).toEqual('');
expect(component.instructorInstitution).toEqual('');
-
- expect(component.accountReqs.length).toEqual(1);
- expect(component.accountReqs[0].name).toEqual('Instructor Name');
- expect(component.accountReqs[0].email).toEqual('instructor@example.com');
- expect(component.accountReqs[0].instituteAndCountry).toEqual('Instructor Institution');
});
- it('validateAndAddInstructorDetail: should not add one instructor to list if some fields are empty', () => {
+ it('validateAndAddInstructorDetail: should not create one instructor account request '
+ + 'if some fields are empty', () => {
const button: any = fixture.debugElement.nativeElement.querySelector('#add-instructor');
+ const createAccountRequestSpy = jest.spyOn(accountService, 'createAccountRequest');
component.instructorName = '';
component.instructorEmail = 'instructor@example.com';
@@ -142,7 +126,7 @@ describe('AdminHomePageComponent', () => {
expect(component.instructorName).toEqual('');
expect(component.instructorEmail).toEqual('instructor@example.com');
expect(component.instructorInstitution).toEqual('Instructor Institution');
- expect(component.accountReqs.length).toEqual(0);
+ expect(createAccountRequestSpy).not.toHaveBeenCalled();
component.instructorName = 'Instructor Name';
component.instructorEmail = '';
@@ -154,7 +138,7 @@ describe('AdminHomePageComponent', () => {
expect(component.instructorName).toEqual('Instructor Name');
expect(component.instructorEmail).toEqual('');
expect(component.instructorInstitution).toEqual('Instructor Institution');
- expect(component.accountReqs.length).toEqual(0);
+ expect(createAccountRequestSpy).not.toHaveBeenCalled();
component.instructorName = 'Instructor Name';
component.instructorEmail = 'instructor@example.com';
@@ -166,10 +150,11 @@ describe('AdminHomePageComponent', () => {
expect(component.instructorName).toEqual('Instructor Name');
expect(component.instructorEmail).toEqual('instructor@example.com');
expect(component.instructorInstitution).toEqual('');
- expect(component.accountReqs.length).toEqual(0);
+ expect(createAccountRequestSpy).not.toHaveBeenCalled();
});
- it('validateAndAddInstructorDetails: should only add valid instructor details in the single line field', () => {
+ it('validateAndAddInstructorDetails: should only create account requests for valid instructor details '
+ + 'when there are invalid lines in the single line field', () => {
component.instructorDetails = [
'Instructor A | instructora@example.com | Institution A',
'Instructor B | instructorb@example.com',
@@ -190,28 +175,7 @@ describe('AdminHomePageComponent', () => {
.instructorInstitution('Institution D')
.build();
- const createAccountRequestSpy = jest.spyOn(accountService, 'createAccountRequest')
- .mockReturnValue(of(accountRequestBuilder.build()));
-
- const accountRequestA = accountRequestBuilder
- .name('Instructor A')
- .email('instructora@example.com')
- .institute('Institution A')
- .build();
- const accountRequestD = accountRequestBuilder
- .name('Instructor D')
- .email('instructord@example.com')
- .institute('Institution D')
- .build();
- const accountRequests: AccountRequests = {
- accountRequests: [
- accountRequestA,
- accountRequestD,
- ],
- };
-
- jest.spyOn(accountService, 'getPendingAccountRequests')
- .mockReturnValue(of(accountRequests));
+ const createAccountRequestSpy = jest.spyOn(accountService, 'createAccountRequest');
const button: any = fixture.debugElement.nativeElement.querySelector('#add-instructor-single-line');
button.click();
@@ -222,18 +186,9 @@ describe('AdminHomePageComponent', () => {
'| instructore@example.com | Institution E',
].join('\r\n'));
+ expect(createAccountRequestSpy).toHaveBeenCalledTimes(2);
expect(createAccountRequestSpy).toHaveBeenNthCalledWith(1, accountCreateRequestA);
expect(createAccountRequestSpy).toHaveBeenNthCalledWith(2, accountCreateRequestD);
-
- expect(component.accountReqs.length).toEqual(2);
-
- expect(component.accountReqs[0].name).toEqual('Instructor A');
- expect(component.accountReqs[0].email).toEqual('instructora@example.com');
- expect(component.accountReqs[0].instituteAndCountry).toEqual('Institution A');
-
- expect(component.accountReqs[1].name).toEqual('Instructor D');
- expect(component.accountReqs[1].email).toEqual('instructord@example.com');
- expect(component.accountReqs[1].instituteAndCountry).toEqual('Institution D');
});
it('should snap with default view', () => {
@@ -274,7 +229,7 @@ describe('AdminHomePageComponent', () => {
expect(fixture).toMatchSnapshot();
});
- it('validateAndAddInstructorDetails: should add multiple instructors split by tabs', () => {
+ it('validateAndAddInstructorDetails: should create multiple instructor account requests when split by tabs', () => {
component.instructorDetails =
`Instructor A \t instructora@example.com \t Sample Institution A\n
Instructor B \t instructorb@example.com \t Sample Institution B`;
@@ -291,28 +246,7 @@ describe('AdminHomePageComponent', () => {
.instructorInstitution('Sample Institution B')
.build();
- const createAccountRequestSpy = jest.spyOn(accountService, 'createAccountRequest')
- .mockReturnValue(of(accountRequestBuilder.build()));
-
- const accountRequestA = accountRequestBuilder
- .name('Instructor A')
- .email('instructora@example.com')
- .institute('Sample Institution A')
- .build();
- const accountRequestB = accountRequestBuilder
- .name('Instructor B')
- .email('instructorb@example.com')
- .institute('Sample Institution B')
- .build();
- const accountRequests: AccountRequests = {
- accountRequests: [
- accountRequestA,
- accountRequestB,
- ],
- };
-
- jest.spyOn(accountService, 'getPendingAccountRequests')
- .mockReturnValue(of(accountRequests));
+ const createAccountRequestSpy = jest.spyOn(accountService, 'createAccountRequest');
const button: any = fixture.debugElement.nativeElement.querySelector('#add-instructor-single-line');
button.click();
@@ -321,19 +255,10 @@ describe('AdminHomePageComponent', () => {
expect(createAccountRequestSpy).toHaveBeenNthCalledWith(1, accountCreateRequestA);
expect(createAccountRequestSpy).toHaveBeenNthCalledWith(2, accountCreateRequestB);
-
- expect(component.accountReqs.length).toEqual(2);
-
- expect(component.accountReqs[0].name).toEqual('Instructor A');
- expect(component.accountReqs[0].email).toEqual('instructora@example.com');
- expect(component.accountReqs[0].instituteAndCountry).toEqual('Sample Institution A');
-
- expect(component.accountReqs[1].name).toEqual('Instructor B');
- expect(component.accountReqs[1].email).toEqual('instructorb@example.com');
- expect(component.accountReqs[1].instituteAndCountry).toEqual('Sample Institution B');
});
- it('validateAndAddInstructorDetails: should add multiple instructors split by vertical bars', () => {
+ it('validateAndAddInstructorDetails: should create multiple instructor account requests '
+ + 'when split by vertical bars', () => {
component.instructorDetails =
`Instructor A | instructora@example.com | Sample Institution A\n
Instructor B | instructorb@example.com | Sample Institution B`;
@@ -350,18 +275,27 @@ describe('AdminHomePageComponent', () => {
.instructorInstitution('Sample Institution B')
.build();
- const createAccountRequestSpy = jest.spyOn(accountService, 'createAccountRequest')
- .mockReturnValue(of(accountRequestBuilder.build()));
+ const createAccountRequestSpy = jest.spyOn(accountService, 'createAccountRequest');
+
+ const button: any = fixture.debugElement.nativeElement.querySelector('#add-instructor-single-line');
+ button.click();
+
+ expect(component.instructorDetails).toEqual('');
+ expect(createAccountRequestSpy).toHaveBeenNthCalledWith(1, accountCreateRequestA);
+ expect(createAccountRequestSpy).toHaveBeenNthCalledWith(2, accountCreateRequestB);
+ });
+
+ it('fetchAccountRequests: should update account requests binding if pending account requests exist', () => {
const accountRequestA = accountRequestBuilder
.name('Instructor A')
.email('instructora@example.com')
- .institute('Sample Institution A')
+ .institute('Institution A')
.build();
const accountRequestB = accountRequestBuilder
.name('Instructor B')
.email('instructorb@example.com')
- .institute('Sample Institution B')
+ .institute('Institution B')
.build();
const accountRequests: AccountRequests = {
accountRequests: [
@@ -373,22 +307,29 @@ describe('AdminHomePageComponent', () => {
jest.spyOn(accountService, 'getPendingAccountRequests')
.mockReturnValue(of(accountRequests));
- const button: any = fixture.debugElement.nativeElement.querySelector('#add-instructor-single-line');
- button.click();
-
- expect(component.instructorDetails).toEqual('');
-
- expect(createAccountRequestSpy).toHaveBeenNthCalledWith(1, accountCreateRequestA);
- expect(createAccountRequestSpy).toHaveBeenNthCalledWith(2, accountCreateRequestB);
+ component.fetchAccountRequests();
expect(component.accountReqs.length).toEqual(2);
expect(component.accountReqs[0].name).toEqual('Instructor A');
expect(component.accountReqs[0].email).toEqual('instructora@example.com');
- expect(component.accountReqs[0].instituteAndCountry).toEqual('Sample Institution A');
+ expect(component.accountReqs[0].instituteAndCountry).toEqual('Institution A');
expect(component.accountReqs[1].name).toEqual('Instructor B');
expect(component.accountReqs[1].email).toEqual('instructorb@example.com');
- expect(component.accountReqs[1].instituteAndCountry).toEqual('Sample Institution B');
+ expect(component.accountReqs[1].instituteAndCountry).toEqual('Institution B');
+ });
+
+ it('fetchAccountRequests: should not update account requests binding if no pending account requests exist', () => {
+ const accountRequests: AccountRequests = {
+ accountRequests: [],
+ };
+
+ jest.spyOn(accountService, 'getPendingAccountRequests')
+ .mockReturnValue(of(accountRequests));
+
+ component.fetchAccountRequests();
+
+ expect(component.accountReqs.length).toEqual(0);
});
});
From b81a48f30cc7456a464120fa210ce5b2d4ccf4a3 Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Mon, 3 Jun 2024 04:34:37 +1200
Subject: [PATCH 10/25] Change sample strings to shorter strings
---
.../admin-home-page.component.spec.ts.snap | 18 +++++-----
.../admin-home-page.component.spec.ts | 34 +++++++++----------
2 files changed, 26 insertions(+), 26 deletions(-)
diff --git a/src/web/app/pages-admin/admin-home-page/__snapshots__/admin-home-page.component.spec.ts.snap b/src/web/app/pages-admin/admin-home-page/__snapshots__/admin-home-page.component.spec.ts.snap
index 15acae8f022..83d1122d34f 100644
--- a/src/web/app/pages-admin/admin-home-page/__snapshots__/admin-home-page.component.spec.ts.snap
+++ b/src/web/app/pages-admin/admin-home-page/__snapshots__/admin-home-page.component.spec.ts.snap
@@ -301,18 +301,18 @@ exports[`AdminHomePageComponent should snap with some instructors details 1`] =
PENDING
- Sample Institution and Country A
+ Institution and Country A
|
- Sample Created Time A
+ Created Time A
|
|
|
- Sample Institution and Country B
+ Institution and Country B
|
- Sample Created Time B
+ Created Time B
|
|
|
- Sample Institution and Country C
+ Institution and Country C
|
- Sample Created Time C
+ Created Time C
|
|
{
.name('Instructor A')
.email('instructora@example.com')
.status(AccountRequestStatus.PENDING)
- .instituteAndCountry('Sample Institution and Country A')
- .createdAtText('Sample Created Time A')
- .comments('Sample Comment A')
+ .instituteAndCountry('Institution and Country A')
+ .createdAtText('Created Time A')
+ .comments('Comment A')
.build(),
accountRequestTableRowModelBuilder
.name('Instructor B')
.email('instructorb@example.com')
.status(AccountRequestStatus.APPROVED)
- .instituteAndCountry('Sample Institution and Country B')
- .createdAtText('Sample Created Time B')
- .comments('Sample Comment B')
+ .instituteAndCountry('Institution and Country B')
+ .createdAtText('Created Time B')
+ .comments('Comment B')
.build(),
accountRequestTableRowModelBuilder
.name('Instructor C')
.email('instructorc@example.com')
.status(AccountRequestStatus.REJECTED)
- .instituteAndCountry('Sample Institution and Country C')
- .createdAtText('Sample Created Time C')
- .comments('Sample Comment C')
+ .instituteAndCountry('Institution and Country C')
+ .createdAtText('Created Time C')
+ .comments('Comment C')
.build(),
];
fixture.detectChanges();
@@ -231,19 +231,19 @@ describe('AdminHomePageComponent', () => {
it('validateAndAddInstructorDetails: should create multiple instructor account requests when split by tabs', () => {
component.instructorDetails =
- `Instructor A \t instructora@example.com \t Sample Institution A\n
- Instructor B \t instructorb@example.com \t Sample Institution B`;
+ `Instructor A \t instructora@example.com \t Institution A\n
+ Instructor B \t instructorb@example.com \t Institution B`;
fixture.detectChanges();
const accountCreateRequestA = accountCreateRequestBuilder
.instructorName('Instructor A')
.instructorEmail('instructora@example.com')
- .instructorInstitution('Sample Institution A')
+ .instructorInstitution('Institution A')
.build();
const accountCreateRequestB = accountCreateRequestBuilder
.instructorName('Instructor B')
.instructorEmail('instructorb@example.com')
- .instructorInstitution('Sample Institution B')
+ .instructorInstitution('Institution B')
.build();
const createAccountRequestSpy = jest.spyOn(accountService, 'createAccountRequest');
@@ -260,19 +260,19 @@ describe('AdminHomePageComponent', () => {
it('validateAndAddInstructorDetails: should create multiple instructor account requests '
+ 'when split by vertical bars', () => {
component.instructorDetails =
- `Instructor A | instructora@example.com | Sample Institution A\n
- Instructor B | instructorb@example.com | Sample Institution B`;
+ `Instructor A | instructora@example.com | Institution A\n
+ Instructor B | instructorb@example.com | Institution B`;
fixture.detectChanges();
const accountCreateRequestA = accountCreateRequestBuilder
.instructorName('Instructor A')
.instructorEmail('instructora@example.com')
- .instructorInstitution('Sample Institution A')
+ .instructorInstitution('Institution A')
.build();
const accountCreateRequestB = accountCreateRequestBuilder
.instructorName('Instructor B')
.instructorEmail('instructorb@example.com')
- .instructorInstitution('Sample Institution B')
+ .instructorInstitution('Institution B')
.build();
const createAccountRequestSpy = jest.spyOn(accountService, 'createAccountRequest');
From 49f4ce1f0c524d5c9b79ef958b7a237f498dcd23 Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Tue, 25 Jun 2024 17:45:09 +1200
Subject: [PATCH 11/25] Update AdminHomePageE2ETest
---
.../e2e/cases/AdminHomePageE2ETest.java | 15 +++++++--------
.../e2e/pageobjects/AdminHomePage.java | 19 +++++++++++++++++++
2 files changed, 26 insertions(+), 8 deletions(-)
diff --git a/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java b/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java
index 014913e639c..a5a07e65371 100644
--- a/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java
+++ b/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java
@@ -26,26 +26,25 @@ public void testAll() {
AdminHomePage homePage = loginAdminToPage(url, AdminHomePage.class);
______TS("Test adding instructors with both valid and invalid details");
-
String name = "AHPUiT Instrúctör WithPlusInEmail";
String email = "AHPUiT+++_.instr1!@gmail.tmt";
String institute = "TEAMMATES Test Institute 1";
-
homePage.queueInstructorForAdding(name, email, institute);
String singleLineDetails = "Instructor With Invalid Email | invalidemail | TEAMMATES Test Institute 1";
-
homePage.queueInstructorForAdding(singleLineDetails);
- homePage.addAllInstructors();
-
- String successMessage = homePage.getMessageForInstructor(0);
- assertTrue(successMessage.contains(
- "Instructor \"AHPUiT Instrúctör WithPlusInEmail\" has been successfully created"));
+ //homePage.addAllInstructors();
+ homePage.clickApproveAccountRequestButton(name, email, institute);
+ /*
String failureMessage = homePage.getMessageForInstructor(1);
assertTrue(failureMessage.contains(
"\"invalidemail\" is not acceptable to TEAMMATES as a/an email because it is not in the correct format."));
+ */
+ String successMessage = homePage.getToastTextContent();
+ assertTrue(successMessage.contains(
+ "Account request was successfully approved. Email has been sent to AHPUiT+++_.instr1!@gmail.tmt."));
}
}
diff --git a/src/e2e/java/teammates/e2e/pageobjects/AdminHomePage.java b/src/e2e/java/teammates/e2e/pageobjects/AdminHomePage.java
index 9316f042077..78086577d50 100644
--- a/src/e2e/java/teammates/e2e/pageobjects/AdminHomePage.java
+++ b/src/e2e/java/teammates/e2e/pageobjects/AdminHomePage.java
@@ -74,6 +74,15 @@ public void addAllInstructors() {
waitForElementToBeClickable(addAllInstructorsButton);
}
+ public void clickApproveAccountRequestButton(String name, String email, String institute) {
+ WebElement accountRequestRow = getAccountRequestRow(name, email, institute);
+ waitForElementPresence(By.cssSelector("[id^='approve-account-request-']"));
+ WebElement approveButton = accountRequestRow.findElement(By.cssSelector("[id^='approve-account-request-']"));
+ waitForElementToBeClickable(approveButton);
+ approveButton.click();
+ waitForPageToLoad();
+ }
+
public String getMessageForInstructor(int i) {
By by = By.id("message-instructor-" + i);
waitForElementVisibility(by);
@@ -84,6 +93,16 @@ public String getMessageForInstructor(int i) {
return element.getText();
}
+ public String getToastTextContent() {
+ By by = By.tagName("tm-toast");
+ waitForElementVisibility(by);
+ WebElement element = browser.driver.findElement(by);
+ if (element == null) {
+ return null;
+ }
+ return element.getText();
+ }
+
public void clickMoreInfoButtonForRegisteredInstructor(int i) {
By by = By.id("instructor-" + i + "-registered-info-button");
waitForElementVisibility(by);
From 0de6816b4dd809f1f0228026f81540ba7cb0bf50 Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Wed, 26 Jun 2024 00:37:25 +1200
Subject: [PATCH 12/25] Update SQL AdminHomePageE2ETest
---
.../teammates/e2e/cases/sql/AdminHomePageE2ETest.java | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/src/e2e/java/teammates/e2e/cases/sql/AdminHomePageE2ETest.java b/src/e2e/java/teammates/e2e/cases/sql/AdminHomePageE2ETest.java
index e4e4d8c3560..de1f8049a89 100644
--- a/src/e2e/java/teammates/e2e/cases/sql/AdminHomePageE2ETest.java
+++ b/src/e2e/java/teammates/e2e/cases/sql/AdminHomePageE2ETest.java
@@ -34,15 +34,13 @@ public void testAll() {
homePage.queueInstructorForAdding(singleLineDetails);
- homePage.addAllInstructors();
-
- String successMessage = homePage.getMessageForInstructor(0);
- assertTrue(successMessage.contains(
- "Instructor \"AHPUiT Instrúctör WithPlusInEmail\" has been successfully created"));
+ //homePage.addAllInstructors();
+ /*
String failureMessage = homePage.getMessageForInstructor(1);
assertTrue(failureMessage.contains(
"\"invalidemail\" is not acceptable to TEAMMATES as a/an email because it is not in the correct format."));
+ */
homePage.reloadPage();
From c481da4ff9f481678157138ec1ce9cc43d889282 Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Wed, 26 Jun 2024 01:19:55 +1200
Subject: [PATCH 13/25] Remove deprecated E2E test functions
---
.../e2e/cases/AdminHomePageE2ETest.java | 6 ------
.../e2e/cases/sql/AdminHomePageE2ETest.java | 8 --------
.../e2e/pageobjects/AdminHomePage.java | 18 ------------------
3 files changed, 32 deletions(-)
diff --git a/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java b/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java
index a5a07e65371..2d0a0f91554 100644
--- a/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java
+++ b/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java
@@ -34,14 +34,8 @@ public void testAll() {
String singleLineDetails = "Instructor With Invalid Email | invalidemail | TEAMMATES Test Institute 1";
homePage.queueInstructorForAdding(singleLineDetails);
- //homePage.addAllInstructors();
homePage.clickApproveAccountRequestButton(name, email, institute);
- /*
- String failureMessage = homePage.getMessageForInstructor(1);
- assertTrue(failureMessage.contains(
- "\"invalidemail\" is not acceptable to TEAMMATES as a/an email because it is not in the correct format."));
- */
String successMessage = homePage.getToastTextContent();
assertTrue(successMessage.contains(
"Account request was successfully approved. Email has been sent to AHPUiT+++_.instr1!@gmail.tmt."));
diff --git a/src/e2e/java/teammates/e2e/cases/sql/AdminHomePageE2ETest.java b/src/e2e/java/teammates/e2e/cases/sql/AdminHomePageE2ETest.java
index de1f8049a89..cf6bccbf5db 100644
--- a/src/e2e/java/teammates/e2e/cases/sql/AdminHomePageE2ETest.java
+++ b/src/e2e/java/teammates/e2e/cases/sql/AdminHomePageE2ETest.java
@@ -34,14 +34,6 @@ public void testAll() {
homePage.queueInstructorForAdding(singleLineDetails);
- //homePage.addAllInstructors();
-
- /*
- String failureMessage = homePage.getMessageForInstructor(1);
- assertTrue(failureMessage.contains(
- "\"invalidemail\" is not acceptable to TEAMMATES as a/an email because it is not in the correct format."));
- */
-
homePage.reloadPage();
______TS("Verify that newly added instructor appears in account request table");
diff --git a/src/e2e/java/teammates/e2e/pageobjects/AdminHomePage.java b/src/e2e/java/teammates/e2e/pageobjects/AdminHomePage.java
index 78086577d50..12d13a68411 100644
--- a/src/e2e/java/teammates/e2e/pageobjects/AdminHomePage.java
+++ b/src/e2e/java/teammates/e2e/pageobjects/AdminHomePage.java
@@ -36,9 +36,6 @@ public class AdminHomePage extends AppPage {
@FindBy (id = "add-instructor-single-line")
private WebElement submitButtonDetailsSingleLineForm;
- @FindBy (id = "add-all-instructors")
- private WebElement addAllInstructorsButton;
-
public AdminHomePage(Browser browser) {
super(browser);
}
@@ -69,11 +66,6 @@ public void queueInstructorForAdding(String instructorDetails) {
click(submitButtonDetailsSingleLineForm);
}
- public void addAllInstructors() {
- click(addAllInstructorsButton);
- waitForElementToBeClickable(addAllInstructorsButton);
- }
-
public void clickApproveAccountRequestButton(String name, String email, String institute) {
WebElement accountRequestRow = getAccountRequestRow(name, email, institute);
waitForElementPresence(By.cssSelector("[id^='approve-account-request-']"));
@@ -83,16 +75,6 @@ public void clickApproveAccountRequestButton(String name, String email, String i
waitForPageToLoad();
}
- public String getMessageForInstructor(int i) {
- By by = By.id("message-instructor-" + i);
- waitForElementVisibility(by);
- WebElement element = browser.driver.findElement(by);
- if (element == null) {
- return null;
- }
- return element.getText();
- }
-
public String getToastTextContent() {
By by = By.tagName("tm-toast");
waitForElementVisibility(by);
From 2dc547f0796913fb9b621ffbae0cdf3f32f9cf6d Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Sun, 4 Aug 2024 21:44:00 +1200
Subject: [PATCH 14/25] Replace getToastTextContent with verifyStatusMessage
---
.../java/teammates/e2e/cases/AdminHomePageE2ETest.java | 4 +---
.../java/teammates/e2e/pageobjects/AdminHomePage.java | 10 ----------
2 files changed, 1 insertion(+), 13 deletions(-)
diff --git a/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java b/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java
index 2d0a0f91554..9a7d85cd559 100644
--- a/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java
+++ b/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java
@@ -36,9 +36,7 @@ public void testAll() {
homePage.clickApproveAccountRequestButton(name, email, institute);
- String successMessage = homePage.getToastTextContent();
- assertTrue(successMessage.contains(
- "Account request was successfully approved. Email has been sent to AHPUiT+++_.instr1!@gmail.tmt."));
+ homePage.verifyStatusMessage("Account request was successfully approved. Email has been sent to AHPUiT+++_.instr1!@gmail.tmt.");
}
}
diff --git a/src/e2e/java/teammates/e2e/pageobjects/AdminHomePage.java b/src/e2e/java/teammates/e2e/pageobjects/AdminHomePage.java
index 12d13a68411..aa9503b45eb 100644
--- a/src/e2e/java/teammates/e2e/pageobjects/AdminHomePage.java
+++ b/src/e2e/java/teammates/e2e/pageobjects/AdminHomePage.java
@@ -75,16 +75,6 @@ public void clickApproveAccountRequestButton(String name, String email, String i
waitForPageToLoad();
}
- public String getToastTextContent() {
- By by = By.tagName("tm-toast");
- waitForElementVisibility(by);
- WebElement element = browser.driver.findElement(by);
- if (element == null) {
- return null;
- }
- return element.getText();
- }
-
public void clickMoreInfoButtonForRegisteredInstructor(int i) {
By by = By.id("instructor-" + i + "-registered-info-button");
waitForElementVisibility(by);
From 9e15d2f38c4cf7200e0c098438ab8b193814b887 Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Sun, 4 Aug 2024 21:47:30 +1200
Subject: [PATCH 15/25] Fix inconsistent whitespacing
---
.../java/teammates/e2e/cases/sql/AdminHomePageE2ETest.java | 5 -----
1 file changed, 5 deletions(-)
diff --git a/src/e2e/java/teammates/e2e/cases/sql/AdminHomePageE2ETest.java b/src/e2e/java/teammates/e2e/cases/sql/AdminHomePageE2ETest.java
index cf6bccbf5db..4e2fac47e47 100644
--- a/src/e2e/java/teammates/e2e/cases/sql/AdminHomePageE2ETest.java
+++ b/src/e2e/java/teammates/e2e/cases/sql/AdminHomePageE2ETest.java
@@ -23,23 +23,18 @@ public void testAll() {
AdminHomePage homePage = loginAdminToPage(url, AdminHomePage.class);
______TS("Test adding instructors with both valid and invalid details");
-
String name = "AHPUiT Instrúctör WithPlusInEmail";
String email = "AHPUiT+++_.instr1!@gmail.tmt";
String institute = "TEAMMATES Test Institute 1";
-
homePage.queueInstructorForAdding(name, email, institute);
String singleLineDetails = "Instructor With Invalid Email | invalidemail | TEAMMATES Test Institute 1";
-
homePage.queueInstructorForAdding(singleLineDetails);
homePage.reloadPage();
______TS("Verify that newly added instructor appears in account request table");
-
homePage.verifyInstructorInAccountRequestTable(name, email, institute);
-
}
}
From 66d4a0eae8d1a757b66abe69fe034d73848a3b85 Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Sun, 4 Aug 2024 21:58:50 +1200
Subject: [PATCH 16/25] Add error handling to batch requests
---
.../pages-admin/admin-home-page/admin-home-page.component.ts | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts b/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts
index ddc88d081d5..1d3e4d7c552 100644
--- a/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts
+++ b/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts
@@ -70,6 +70,11 @@ export class AdminHomePageComponent implements OnInit {
next: () => {
this.fetchAccountRequests();
},
+ error: (resp: ErrorMessageOutput) => {
+ invalidLines.push(instructorDetail);
+ this.instructorDetails = invalidLines.join('\r\n');
+ this.statusMessageService.showErrorToast(resp.error.message);
+ },
});
}
this.instructorDetails = invalidLines.join('\r\n');
From 7862935e9b82a73377c4e7f5012f12748937a7f3 Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Tue, 6 Aug 2024 14:46:52 +1200
Subject: [PATCH 17/25] Add negative test case for invalid single line email
---
src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java b/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java
index 9a7d85cd559..a0dad3e5afa 100644
--- a/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java
+++ b/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java
@@ -33,6 +33,10 @@ public void testAll() {
String singleLineDetails = "Instructor With Invalid Email | invalidemail | TEAMMATES Test Institute 1";
homePage.queueInstructorForAdding(singleLineDetails);
+ homePage.verifyStatusMessage("\"invalidemail\" is not acceptable to TEAMMATES as a/an email because it is not "
+ + "in the correct format. An email address contains some text followed by one '@' sign followed by some "
+ + "more text, and should end with a top level domain address like .com. It cannot be longer than 254 "
+ + "characters, cannot be empty and cannot contain spaces.");
homePage.clickApproveAccountRequestButton(name, email, institute);
From 28e5c9791765ac5d2383727ba5ea1de3b5258c94 Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Tue, 6 Aug 2024 15:35:35 +1200
Subject: [PATCH 18/25] Fix mismatching logic between sql and non sql test
---
.../java/teammates/e2e/cases/AdminHomePageE2ETest.java | 5 ++++-
.../teammates/e2e/cases/sql/AdminHomePageE2ETest.java | 10 ++++++++--
2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java b/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java
index a0dad3e5afa..858f4578d87 100644
--- a/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java
+++ b/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java
@@ -38,8 +38,11 @@ public void testAll() {
+ "more text, and should end with a top level domain address like .com. It cannot be longer than 254 "
+ "characters, cannot be empty and cannot contain spaces.");
- homePage.clickApproveAccountRequestButton(name, email, institute);
+ ______TS("Verify that newly added instructor appears in account request table");
+ homePage.verifyInstructorInAccountRequestTable(name, email, institute);
+ ______TS("Test approving a valid account request");
+ homePage.clickApproveAccountRequestButton(name, email, institute);
homePage.verifyStatusMessage("Account request was successfully approved. Email has been sent to AHPUiT+++_.instr1!@gmail.tmt.");
}
diff --git a/src/e2e/java/teammates/e2e/cases/sql/AdminHomePageE2ETest.java b/src/e2e/java/teammates/e2e/cases/sql/AdminHomePageE2ETest.java
index 4e2fac47e47..32428e6ee98 100644
--- a/src/e2e/java/teammates/e2e/cases/sql/AdminHomePageE2ETest.java
+++ b/src/e2e/java/teammates/e2e/cases/sql/AdminHomePageE2ETest.java
@@ -30,11 +30,17 @@ public void testAll() {
String singleLineDetails = "Instructor With Invalid Email | invalidemail | TEAMMATES Test Institute 1";
homePage.queueInstructorForAdding(singleLineDetails);
-
- homePage.reloadPage();
+ homePage.verifyStatusMessage("\"invalidemail\" is not acceptable to TEAMMATES as a/an email because it is not "
+ + "in the correct format. An email address contains some text followed by one '@' sign followed by some "
+ + "more text, and should end with a top level domain address like .com. It cannot be longer than 254 "
+ + "characters, cannot be empty and cannot contain spaces.");
______TS("Verify that newly added instructor appears in account request table");
homePage.verifyInstructorInAccountRequestTable(name, email, institute);
+
+ ______TS("Test approving a valid account request");
+ homePage.clickApproveAccountRequestButton(name, email, institute);
+ homePage.verifyStatusMessage("Account request was successfully approved. Email has been sent to AHPUiT+++_.instr1!@gmail.tmt.");
}
}
From 7a954f7ace0a5d4f95ed95a90b29bf672ca30f26 Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Tue, 6 Aug 2024 16:18:41 +1200
Subject: [PATCH 19/25] Fix linting
---
.../java/teammates/e2e/cases/AdminHomePageE2ETest.java | 9 +++++----
.../teammates/e2e/cases/sql/AdminHomePageE2ETest.java | 9 +++++----
2 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java b/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java
index 858f4578d87..b1982ab798b 100644
--- a/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java
+++ b/src/e2e/java/teammates/e2e/cases/AdminHomePageE2ETest.java
@@ -34,16 +34,17 @@ public void testAll() {
String singleLineDetails = "Instructor With Invalid Email | invalidemail | TEAMMATES Test Institute 1";
homePage.queueInstructorForAdding(singleLineDetails);
homePage.verifyStatusMessage("\"invalidemail\" is not acceptable to TEAMMATES as a/an email because it is not "
- + "in the correct format. An email address contains some text followed by one '@' sign followed by some "
- + "more text, and should end with a top level domain address like .com. It cannot be longer than 254 "
- + "characters, cannot be empty and cannot contain spaces.");
+ + "in the correct format. An email address contains some text followed by one '@' sign followed by some "
+ + "more text, and should end with a top level domain address like .com. It cannot be longer than 254 "
+ + "characters, cannot be empty and cannot contain spaces.");
______TS("Verify that newly added instructor appears in account request table");
homePage.verifyInstructorInAccountRequestTable(name, email, institute);
______TS("Test approving a valid account request");
homePage.clickApproveAccountRequestButton(name, email, institute);
- homePage.verifyStatusMessage("Account request was successfully approved. Email has been sent to AHPUiT+++_.instr1!@gmail.tmt.");
+ homePage.verifyStatusMessage("Account request was successfully approved. Email has been sent to "
+ + "AHPUiT+++_.instr1!@gmail.tmt.");
}
}
diff --git a/src/e2e/java/teammates/e2e/cases/sql/AdminHomePageE2ETest.java b/src/e2e/java/teammates/e2e/cases/sql/AdminHomePageE2ETest.java
index 32428e6ee98..4335ab6a226 100644
--- a/src/e2e/java/teammates/e2e/cases/sql/AdminHomePageE2ETest.java
+++ b/src/e2e/java/teammates/e2e/cases/sql/AdminHomePageE2ETest.java
@@ -31,16 +31,17 @@ public void testAll() {
String singleLineDetails = "Instructor With Invalid Email | invalidemail | TEAMMATES Test Institute 1";
homePage.queueInstructorForAdding(singleLineDetails);
homePage.verifyStatusMessage("\"invalidemail\" is not acceptable to TEAMMATES as a/an email because it is not "
- + "in the correct format. An email address contains some text followed by one '@' sign followed by some "
- + "more text, and should end with a top level domain address like .com. It cannot be longer than 254 "
- + "characters, cannot be empty and cannot contain spaces.");
+ + "in the correct format. An email address contains some text followed by one '@' sign followed by some "
+ + "more text, and should end with a top level domain address like .com. It cannot be longer than 254 "
+ + "characters, cannot be empty and cannot contain spaces.");
______TS("Verify that newly added instructor appears in account request table");
homePage.verifyInstructorInAccountRequestTable(name, email, institute);
______TS("Test approving a valid account request");
homePage.clickApproveAccountRequestButton(name, email, institute);
- homePage.verifyStatusMessage("Account request was successfully approved. Email has been sent to AHPUiT+++_.instr1!@gmail.tmt.");
+ homePage.verifyStatusMessage("Account request was successfully approved. Email has been sent to "
+ + "AHPUiT+++_.instr1!@gmail.tmt.");
}
}
From 3cbf5a0f7c4bb6d4d50b7af13c3de938f89c4e0f Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Thu, 15 Aug 2024 20:46:45 +1200
Subject: [PATCH 20/25] Fix api being called multiple times
---
.../admin-home-page.component.ts | 55 +++++++++----------
1 file changed, 27 insertions(+), 28 deletions(-)
diff --git a/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts b/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts
index 1d3e4d7c552..69c1df98c3a 100644
--- a/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts
+++ b/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts
@@ -44,40 +44,39 @@ export class AdminHomePageComponent implements OnInit {
/**
* Validates and adds the instructor details filled with first form.
*/
- validateAndAddInstructorDetails(): void {
- const invalidLines: string[] = [];
- for (const instructorDetail of this.instructorDetails.split(/\r?\n/)) {
- const instructorDetailSplit: string[] = instructorDetail.split(/[|\t]/).map((item: string) => item.trim());
- if (instructorDetailSplit.length < 3) {
- // TODO handle error
- invalidLines.push(instructorDetail);
- continue;
- }
- if (!instructorDetailSplit[0] || !instructorDetailSplit[1] || !instructorDetailSplit[2]) {
- // TODO handle error
- invalidLines.push(instructorDetail);
- continue;
- }
+validateAndAddInstructorDetails(): void {
+ const lines: string[] = this.instructorDetails.split(/\r?\n/);
+ const accountRequests: Promise[] = [];
+ for (const line of lines) {
+ const instructorDetailsSplit: string[] = line.split(/[|\t]/).map((item: string) => item.trim());
const requestData: AccountCreateRequest = {
- instructorEmail: instructorDetailSplit[1],
- instructorName: instructorDetailSplit[0],
- instructorInstitution: instructorDetailSplit[2],
+ instructorEmail: instructorDetailsSplit[1],
+ instructorName: instructorDetailsSplit[0],
+ instructorInstitution: instructorDetailsSplit[2],
};
- this.accountService.createAccountRequest(requestData)
- .subscribe({
- next: () => {
- this.fetchAccountRequests();
- },
- error: (resp: ErrorMessageOutput) => {
- invalidLines.push(instructorDetail);
- this.instructorDetails = invalidLines.join('\r\n');
- this.statusMessageService.showErrorToast(resp.error.message);
- },
+ const newRequest: Promise = new Promise((resolve, reject) => {
+ this.accountService.createAccountRequest(requestData)
+ .subscribe({
+ next: () => {
+ lines.splice(lines.indexOf(line), 1);
+ resolve();
+ },
+ error: (resp: ErrorMessageOutput) => {
+ this.statusMessageService.showErrorToast(resp.error.message);
+ reject();
+ },
+ });
});
+
+ accountRequests.push(newRequest);
}
- this.instructorDetails = invalidLines.join('\r\n');
+
+ Promise.allSettled(accountRequests).then(() => {
+ this.instructorDetails = lines.join('\r\n');
+ this.fetchAccountRequests();
+ });
}
/**
From 7d5fecab1d54aa43384fb3130c90e25534f5a838 Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Wed, 28 Aug 2024 21:49:11 +1200
Subject: [PATCH 21/25] Fix loop array being changed inside loop
---
.../admin-home-page/admin-home-page.component.ts | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts b/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts
index 69c1df98c3a..0e3b08dafbb 100644
--- a/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts
+++ b/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts
@@ -44,8 +44,9 @@ export class AdminHomePageComponent implements OnInit {
/**
* Validates and adds the instructor details filled with first form.
*/
-validateAndAddInstructorDetails(): void {
+ validateAndAddInstructorDetails(): void {
const lines: string[] = this.instructorDetails.split(/\r?\n/);
+ const invalidLines: string[] = [];
const accountRequests: Promise[] = [];
for (const line of lines) {
const instructorDetailsSplit: string[] = line.split(/[|\t]/).map((item: string) => item.trim());
@@ -60,10 +61,10 @@ validateAndAddInstructorDetails(): void {
this.accountService.createAccountRequest(requestData)
.subscribe({
next: () => {
- lines.splice(lines.indexOf(line), 1);
resolve();
},
error: (resp: ErrorMessageOutput) => {
+ invalidLines.push(line);
this.statusMessageService.showErrorToast(resp.error.message);
reject();
},
@@ -74,7 +75,7 @@ validateAndAddInstructorDetails(): void {
}
Promise.allSettled(accountRequests).then(() => {
- this.instructorDetails = lines.join('\r\n');
+ this.instructorDetails = invalidLines.join('\r\n');
this.fetchAccountRequests();
});
}
From 0fa111bf7f8ae315df443f57c7e2cd7259c0f68b Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Wed, 28 Aug 2024 21:50:57 +1200
Subject: [PATCH 22/25] Change validateAndAddInstructorDetails() return from
void to Promise
---
.../pages-admin/admin-home-page/admin-home-page.component.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts b/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts
index 0e3b08dafbb..99c863ccdfc 100644
--- a/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts
+++ b/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts
@@ -44,7 +44,7 @@ export class AdminHomePageComponent implements OnInit {
/**
* Validates and adds the instructor details filled with first form.
*/
- validateAndAddInstructorDetails(): void {
+ validateAndAddInstructorDetails(): Promise {
const lines: string[] = this.instructorDetails.split(/\r?\n/);
const invalidLines: string[] = [];
const accountRequests: Promise[] = [];
@@ -74,7 +74,7 @@ export class AdminHomePageComponent implements OnInit {
accountRequests.push(newRequest);
}
- Promise.allSettled(accountRequests).then(() => {
+ return Promise.allSettled(accountRequests).then(() => {
this.instructorDetails = invalidLines.join('\r\n');
this.fetchAccountRequests();
});
From a2f3b4fe5ab155eed71c5dadab95f3dc072203c9 Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Thu, 29 Aug 2024 00:05:21 +1200
Subject: [PATCH 23/25] Add string checks before request creation
---
.../admin-home-page.component.ts | 46 +++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts b/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts
index 99c863ccdfc..eee88e6149c 100644
--- a/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts
+++ b/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts
@@ -50,6 +50,52 @@ export class AdminHomePageComponent implements OnInit {
const accountRequests: Promise[] = [];
for (const line of lines) {
const instructorDetailsSplit: string[] = line.split(/[|\t]/).map((item: string) => item.trim());
+ let errorMessage = '';
+ switch (instructorDetailsSplit.length) {
+ case 1:
+ // Triggers when instructorDetails is empty
+ if (!instructorDetailsSplit[0]) {
+ continue;
+ }
+
+ invalidLines.push(line);
+ this.statusMessageService.showErrorToast('email cannot be null');
+ continue;
+ case 2:
+ invalidLines.push(line);
+ this.statusMessageService.showErrorToast('institution cannot be null');
+ continue;
+ case 3:
+ break;
+ default:
+ invalidLines.push(line);
+ this.statusMessageService.showErrorToast('Too many fields, please check that all lines contains only a '
+ + 'name, email and institution.');
+ continue;
+ }
+
+ // Update the character numbers if it changes in the backend.
+ if (!instructorDetailsSplit[0]) {
+ errorMessage = 'The field \'person name\' is empty. '
+ + 'The value of a/an person name should be no longer than 100 characters. '
+ + 'It should not be empty.\n';
+ }
+ if (!instructorDetailsSplit[1]) {
+ errorMessage += 'The field \'email\' is empty. '
+ + 'An email address contains some text followed by one \'@\' sign followed by some more text, '
+ + 'and should end with a top level domain address like .com. '
+ + 'It cannot be longer than 254 characters, cannot be empty and cannot contain spaces.\n';
+ }
+ if (!instructorDetailsSplit[2]) {
+ errorMessage += 'The field \'institute name\' is empty. '
+ + 'The value of a/an institute name should be no longer than 128 characters. '
+ + 'It should not be empty.';
+ }
+ if (errorMessage !== '') {
+ invalidLines.push(line);
+ this.statusMessageService.showErrorToast(errorMessage);
+ break;
+ }
const requestData: AccountCreateRequest = {
instructorEmail: instructorDetailsSplit[1],
From 266a37e19a39e70e58c5b11e0d2ecf1a94b5eb1d Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Thu, 29 Aug 2024 00:35:02 +1200
Subject: [PATCH 24/25] Fix break used instead of continue in for loop
---
.../pages-admin/admin-home-page/admin-home-page.component.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts b/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts
index eee88e6149c..75c69675bdd 100644
--- a/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts
+++ b/src/web/app/pages-admin/admin-home-page/admin-home-page.component.ts
@@ -94,7 +94,7 @@ export class AdminHomePageComponent implements OnInit {
if (errorMessage !== '') {
invalidLines.push(line);
this.statusMessageService.showErrorToast(errorMessage);
- break;
+ continue;
}
const requestData: AccountCreateRequest = {
From 3351df8b029c97c7666bbdf75010ebdf711831b3 Mon Sep 17 00:00:00 2001
From: Andy Wang <128531452+Andy-W-Developer@users.noreply.github.com>
Date: Thu, 29 Aug 2024 00:44:42 +1200
Subject: [PATCH 25/25] Add mock implementation for createAccountRequest
---
.../admin-home-page.component.spec.ts | 50 +++++++++++++++++--
1 file changed, 45 insertions(+), 5 deletions(-)
diff --git a/src/web/app/pages-admin/admin-home-page/admin-home-page.component.spec.ts b/src/web/app/pages-admin/admin-home-page/admin-home-page.component.spec.ts
index f373115204e..b410774f40e 100644
--- a/src/web/app/pages-admin/admin-home-page/admin-home-page.component.spec.ts
+++ b/src/web/app/pages-admin/admin-home-page/admin-home-page.component.spec.ts
@@ -2,19 +2,20 @@ import { HttpClientTestingModule } from '@angular/common/http/testing';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { FormsModule } from '@angular/forms';
import { RouterTestingModule } from '@angular/router/testing';
-import { of } from 'rxjs';
+import { of, throwError } from 'rxjs';
import { AdminHomePageComponent } from './admin-home-page.component';
import { NewInstructorDataRowComponent } from './new-instructor-data-row/new-instructor-data-row.component';
import { AccountService } from '../../../services/account.service';
import { StatusMessageService } from '../../../services/status-message.service';
import { createBuilder } from '../../../test-helpers/generic-builder';
-import { AccountRequest, AccountRequests, AccountRequestStatus } from '../../../types/api-output';
+import { AccountRequest, AccountRequests, AccountRequestStatus, MessageOutput } from '../../../types/api-output';
import { AccountCreateRequest } from '../../../types/api-request';
import { AccountRequestTableRowModel } from '../../components/account-requests-table/account-request-table-model';
import { AccountRequestTableModule } from '../../components/account-requests-table/account-request-table.module';
import { AjaxLoadingModule } from '../../components/ajax-loading/ajax-loading.module';
import { LoadingSpinnerModule } from '../../components/loading-spinner/loading-spinner.module';
import { FormatDateDetailPipe } from '../../components/teammates-common/format-date-detail.pipe';
+import { ErrorMessageOutput } from '../../error-message-output';
const accountCreateRequestBuilder = createBuilder({
instructorEmail: '',
@@ -32,6 +33,15 @@ const accountRequestBuilder = createBuilder({
createdAt: 0,
});
+const messageOutputBuilder = createBuilder({
+ message: '',
+});
+
+const errorMessageOutputBuilder = createBuilder({
+ error: messageOutputBuilder.build(),
+ status: 0,
+});
+
const accountRequestTableRowModelBuilder = createBuilder({
id: '',
name: '',
@@ -175,7 +185,17 @@ describe('AdminHomePageComponent', () => {
.instructorInstitution('Institution D')
.build();
- const createAccountRequestSpy = jest.spyOn(accountService, 'createAccountRequest');
+ const createAccountRequestSpy = jest.spyOn(accountService, 'createAccountRequest')
+ .mockImplementation((request) => {
+ switch (request.instructorEmail) {
+ case accountCreateRequestA.instructorEmail:
+ return of(accountRequestBuilder.build());
+ case accountCreateRequestD.instructorEmail:
+ return of(accountRequestBuilder.build());
+ default:
+ return throwError(() => errorMessageOutputBuilder.build());
+ }
+ });
const button: any = fixture.debugElement.nativeElement.querySelector('#add-instructor-single-line');
button.click();
@@ -246,7 +266,17 @@ describe('AdminHomePageComponent', () => {
.instructorInstitution('Institution B')
.build();
- const createAccountRequestSpy = jest.spyOn(accountService, 'createAccountRequest');
+ const createAccountRequestSpy = jest.spyOn(accountService, 'createAccountRequest')
+ .mockImplementation((request) => {
+ switch (request.instructorEmail) {
+ case accountCreateRequestA.instructorEmail:
+ return of(accountRequestBuilder.build());
+ case accountCreateRequestB.instructorEmail:
+ return of(accountRequestBuilder.build());
+ default:
+ return throwError(() => errorMessageOutputBuilder.build());
+ }
+ });
const button: any = fixture.debugElement.nativeElement.querySelector('#add-instructor-single-line');
button.click();
@@ -275,7 +305,17 @@ describe('AdminHomePageComponent', () => {
.instructorInstitution('Institution B')
.build();
- const createAccountRequestSpy = jest.spyOn(accountService, 'createAccountRequest');
+ const createAccountRequestSpy = jest.spyOn(accountService, 'createAccountRequest')
+ .mockImplementation((request) => {
+ switch (request.instructorEmail) {
+ case accountCreateRequestA.instructorEmail:
+ return of(accountRequestBuilder.build());
+ case accountCreateRequestB.instructorEmail:
+ return of(accountRequestBuilder.build());
+ default:
+ return throwError(() => errorMessageOutputBuilder.build());
+ }
+ });
const button: any = fixture.debugElement.nativeElement.querySelector('#add-instructor-single-line');
button.click();
|