-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[#11878] Merge master into feature #13011
Merged
ziqing26
merged 31 commits into
TEAMMATES:account-request-form
from
ziqing26:account-request-form
Apr 13, 2024
Merged
Changes from all commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
9a099c1
Update chrome driver download link in e2e-testing.md (#12924)
nadasuhailAyesh12 e0c6a2d
[#12048] Add SQL configuration into build.properties and build-dev.pr…
FergusMok 845009e
[#12048] Add SQL description for postgres config (#12931)
FergusMok 3499d2a
[#12588] Improve test code coverage of core components - ToastCompone…
techMedMau 7ba20fc
[#12588] Add unit tests to question edit answer form (#12935)
cedricongjh 1be2adb
add delay to task queuer for indexing account request (#12936)
cedricongjh 716fdc4
Make account req data migration script rerunnable (#12932)
ziqing26 ca20709
[#12048] Relax read notif verification for migration verification scr…
NicolasCwy e435f17
[#12920] Create script to migrate noSQL test data to SQL schema forma…
NicolasCwy a02f444
[#12588] Improve test code coverage of core components - ViewResultsP…
techMedMau 11b8b81
fix resetAccountAction (#12934)
cedricongjh 0cfadef
[#12048] Migrate Feedback Rank Option E2E test (#12902)
mingyuanc e51132e
[#12048] Migrate FeedbackMcqQuestionE2ETest (#12820)
dishenggg 20df6b6
[#12048] Remove unnecessary loading of datastore entities in Instruct…
dishenggg a9423da
[#12048] Migrate InstructorCourseDetailsPageE2ETest (#12908)
jayasting98 78eee47
[#12588] add unit tests for question submission form (#12897)
cedricongjh 9d0cf37
Update developers.json (#12958)
cedricongjh c4fe140
Merge pull request #12960 from TEAMMATES/master (#12961)
cedricongjh 356c318
[#12048] Fix account request indexing (#12967)
cedricongjh 2ee4269
configure agroal connection pool (#12971)
cedricongjh 38dbf29
[#12048] Configure connection pool using hikari (#12978)
FergusMok 028c953
[#12048] Update liquibase configuration (#12930)
NicolasCwy 1e9ccb0
[#12048] Migrate AccountRequestsLogicTest (#12780)
xenosf 84ed244
[#12048] Migrate AdminSearchPageE2ETest SQL (#12811)
domoberzin db0fd94
[#12995] Create documentation for unit tests (#12996)
cedricongjh 6c420fa
[#12048] Remove feedbackSession attributes @fetch annotation (#12992)
NicolasCwy 8f43cc8
[#12048] create skeleton for sql LNP tests (#12994)
cedricongjh b9ccd4f
[#12048] Migrate FeedbackNumScaleQuestionE2ETest (#12940)
marquestye 2354975
Add v9.0.0 tag to liquibase changelog (#13005)
NicolasCwy fb7c4e8
sort courses by id before comparison (#13003)
cedricongjh 4595cf3
Merge branch 'master' into account-request-form
ziqing26 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<frontmatter> | ||
title: "Schema Migration" | ||
</frontmatter> | ||
|
||
# SQL Schema Migration | ||
|
||
Teammates uses _[Liquibase]_(https://docs.liquibase.com/start/home.html), a database schema change management solution that enables developers to revise and release database changes to production. The maintainers in charge of releases (Release Leader) will be in charge of generating a _Liquibase_ changelog prior to each release to keep the production databases schema in sync with the code. Therefore this section is just for documentation purposes for contributors. | ||
|
||
## Liquibase in Teammates | ||
_Liquibase_ is made available using the [gradle plugin](https://github.com/liquibase/liquibase-gradle-plugin), providing _liquibase_ functions as tasks. Try `gradle tasks | grep "liquibase"` to see all the tasks available. In teammates, change logs (more in the next section) are written in _XML_. | ||
|
||
### Liquibase connection | ||
Amend the `liquibaseDbUrl`, `liquibaseUsername` and `liquibasePassword` in `gradle.properties` to allow the _Liquibase_ plugin to connect your database. | ||
|
||
## Change logs, change sets and change types | ||
A _change log_ is a file that contains a series of _change sets_ (analagous to a transaction) which applies _change types_ (actions). You can refer to this page on liquibase on the types of [change types](https://docs.liquibase.com/change-types/home.html) that can be used. | ||
|
||
## Gradle Activities for Liquibase | ||
Activities in Gradle are a way of specifying different variables provided by gradle to the Liquibase plugin. The argument `runList` provided by `-pRunList=<activity_name>` e.g `./gradlew liquibaseSnapshot -PrunList=snapshot` is used to specify which activity to be used for the Liquibase command. In this case the `liquibaseSnapshot` command is run using the `snapshot` activity. | ||
|
||
Here is a brief description of the activities defined for Liquibase | ||
1. Main: The default activity used by Liquibase commands and is used for running changelogs against a database. This is used by default if a `runList` is not defined | ||
2. Snapshot: Used to specify output format and name for snapshots i.e JSON | ||
3. diffMain: Specify the reference and the target database to generate changelog that contains operations to update reference database to the state of the target database. i.e the reference is the JSON file generated by the snapshot command, this can be replaced with a live database which is used as reference. | ||
|
||
## Generating/ Updating liquibase change logs | ||
1. Ensure `diff-main` activity in `build.gradle` is pointing to the latest release changelog `src/main/resources/db/changelog/db.changelog-<release_number>.xml` | ||
2. Delete the `postgres-data` folder to clear any old database schemas | ||
3. Run `git checkout <reference_branch>` and | ||
4. Run the server using `./gradlew serverRun` to generate tables found on branch | ||
5. Generate snapshot of database by running `./gradlew liquibaseSnapshot -PrunList=snapshot`, the snapshot will be output to `liquibase-snapshot.json` | ||
6. Checkout your branch and repeat steps 2 and 4 to generate the tables found on your branch | ||
7. Run `./gradlew liquibaseDiffChangeLog -PrunList=diffMain` to generate changeLog to resolve database schema differences | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
<frontmatter> | ||
title: "Unit Testing" | ||
</frontmatter> | ||
|
||
# Unit Testing | ||
|
||
## What is Unit Testing? | ||
|
||
Unit testing is a testing methodology where the objective is to test components in isolation. | ||
|
||
- It aims to ensure all components of the application work as expected, assuming its dependencies are working. | ||
- This is done in TEAMMATES by using mocks to simulate a component's dependencies. | ||
|
||
Frontend Unit tests in TEAMMATES are located in `.spec.ts` files, while Backend Unit tests in TEAMMATES can be found in the package `teammates.test`. | ||
|
||
|
||
## Writing Unit Tests | ||
|
||
### General guidelines | ||
|
||
#### Include only relevant details in tests | ||
When writing unit tests, reduce the amount of noise in the code to make it easier for future developers to follow. | ||
|
||
The code below has a lot of noise in creation of the `studentModel`: | ||
|
||
```javascript | ||
it('displayInviteButton: should display "Send Invite" button when a student has not joined the course', () => { | ||
component.studentModels = [ | ||
{ | ||
student: { | ||
name: 'tester', | ||
teamName: 'Team 1', | ||
email: 'tester@tester.com', | ||
joinState: JoinState.NOT_JOINED, | ||
sectionName: 'Tutorial Group 1', | ||
courseId: 'text-exa.demo', | ||
}, | ||
isAllowedToViewStudentInSection: true, | ||
isAllowedToModifyStudent: true, | ||
}, | ||
]; | ||
|
||
expect(sendInviteButton).toBeTruthy(); | ||
}); | ||
``` | ||
|
||
However, what is important is only the student joinState. We should thus reduce the noise by including only the relevant details: | ||
|
||
```javascript | ||
it('displayInviteButton: should display "Send Invite" button when a student has not joined the course', () => { | ||
component.studentModels = [ | ||
studentModelBuilder | ||
.joinState(JoinState.NOT_JOINED) | ||
.build() | ||
]; | ||
|
||
expect(sendInviteButton).toBeTruthy(); | ||
}); | ||
``` | ||
|
||
Including only the relevant details in tests makes it easier for future developers to read and understand the purpose of the test. | ||
|
||
#### Favor readability over uniqueness | ||
Since tests don't have tests, it should be easy for developers to manually inspect them for correctness, even at the expense of greater code duplication. | ||
|
||
Take the following test for example: | ||
|
||
```java | ||
@BeforeMethod | ||
public void setUp() { | ||
users = new User[]{new User("alice"), new User("bob")}; | ||
} | ||
|
||
@Test | ||
public void test_register_canRegisterMultipleUsers() { | ||
registerAllUsers(); | ||
for (User user : users) { | ||
assertTrue(forum.hasRegisteredUser(user)); | ||
} | ||
} | ||
|
||
private void registerAllUsers() { | ||
for (User user : users) { | ||
forum.register(user); | ||
} | ||
} | ||
``` | ||
|
||
While the code reduces duplication, it is not as straightforward for a developer to follow. | ||
|
||
A more readable way to write this test would be: | ||
```java | ||
@Test | ||
public void test_register_canRegisterMultipleUsers() { | ||
User user1 = new User("alice"); | ||
User user2 = new User("bob"); | ||
|
||
forum.register(user1); | ||
forum.register(user2); | ||
|
||
assertTrue(forum.hasRegisteredUser(user1)); | ||
assertTrue(forum.hasRegisteredUser(user2)); | ||
} | ||
``` | ||
|
||
By choosing readability over uniqueness in writing unit tests, there is code duplication, but the test flow is easier for a reader to follow. | ||
|
||
|
||
#### Inline mocks in test code | ||
|
||
Inlining mock return values in the unit test itself improves readability: | ||
|
||
```javascript | ||
it('getStudentCourseJoinStatus: should return true if student has joined the course' , () => { | ||
jest.spyOn(courseService, 'getJoinCourseStatus') | ||
.mockReturnValue(of({ hasJoined: true })); | ||
|
||
expect(student.getJoinCourseStatus).toBeTruthy(); | ||
}); | ||
``` | ||
|
||
By injecting the values in the test right before they are used, developers are able to more easily trace the code and understand the test. | ||
|
||
### Frontend | ||
|
||
#### Naming | ||
Unit tests for a function should follow the format: | ||
|
||
`"<function-name>: should ... when/if ..."` | ||
|
||
Example: | ||
|
||
```javascript | ||
it('hasSection: should return false when there are no sections in the course') | ||
``` | ||
|
||
#### Creating test data | ||
To aid with [including only relevant details in tests](#include-only-relevant-details-in-tests), use the builder in `src/web/test-helpers/generic-builder.ts` | ||
|
||
Usage: | ||
```javascript | ||
const instructorModelBuilder = createBuilder<InstructorListInfoTableRowModel>({ | ||
email: 'instructor@gmail.com', | ||
name: 'Instructor', | ||
hasSubmittedSession: false, | ||
isSelected: false, | ||
}); | ||
|
||
it('isAllInstructorsSelected: should return false if at least one instructor !isSelected', () => { | ||
component.instructorListInfoTableRowModels = [ | ||
instructorModelBuilder.isSelected(true).build(), | ||
instructorModelBuilder.isSelected(false).build(), | ||
instructorModelBuilder.isSelected(true).build(), | ||
]; | ||
|
||
expect(component.isAllInstructorsSelected).toBeFalsy(); | ||
}); | ||
|
||
``` | ||
|
||
#### Testing event emission | ||
In Angular, child components emit events. To test for event emissions, we've provided a utility function in `src/test-helpers/test-event-emitter` | ||
|
||
Usage: | ||
```javascript | ||
@Output() | ||
deleteCommentEvent: EventEmitter<number> = new EventEmitter(); | ||
|
||
triggerDeleteCommentEvent(index: number): void { | ||
this.deleteCommentEvent.emit(index); | ||
} | ||
|
||
it('triggerDeleteCommentEvent: should emit the correct index to deleteCommentEvent', () => { | ||
let emittedIndex: number | undefined; | ||
testEventEmission(component.deleteCommentEvent, (index) => { emittedIndex = index; }); | ||
|
||
component.triggerDeleteCommentEvent(5); | ||
expect(emittedIndex).toBe(5); | ||
}); | ||
``` | ||
|
||
### Backend | ||
|
||
#### Naming | ||
Unit test names should follow the format: `test<functionName>_<scenario>_<outcome>` | ||
|
||
Examples: | ||
```java | ||
public void testGetComment_commentDoesNotExist_returnsNull() | ||
public void testCreateComment_commentDoesNotExist_success() | ||
public void testCreateComment_commentAlreadyExists_throwsEntityAlreadyExistsException() | ||
``` | ||
|
||
#### Creating test data | ||
To aid with [including only relevant details in tests](#include-only-relevant-details-in-tests), use the `getTypicalX` functions in `BaseTestCase`, where X represents an entity. | ||
|
||
Example: | ||
```java | ||
Account account = getTypicalAccount(); | ||
account.setEmail("newemail@teammates.com"); | ||
|
||
Student student = getTypicalStudent(); | ||
student.setName("New Student Name"); | ||
``` | ||
|
||
<include src="development.md#running-tests" /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here are some of my formatter problems that we did not catch last time. This reverts the formatter change to be the same as on master