Component tests are white-box tests that test the application at two levels:
| Type | Location | Configuration |
|---|---|---|
| Frontend unit tests | *.spec.ts files | src/web/jest.config.js |
| Backend unit tests | teammates.test package | src/test/resources/testng-component.xml |
| Backend integration tests | teammates.it package | src/it/resources/testng-it.xml |
Frontend:
npm run test
This runs tests in watch mode — any changes to source code will automatically reload the tests.
To run tests once and generate coverage data:
npm run coverage
To run an individual test, change it to fit in the relevant *.spec.ts file.
Backend:
| Test suite | Command | Results |
|---|---|---|
| All component tests | ./gradlew componentTests --continue | build/reports/tests/componentTests/index.html |
| Individual test | ./gradlew componentTests --tests TestClassName | build/reports/tests/componentTests/index.html |
To generate coverage data:
./gradlew componentTests jacocoReport
Backend:
| Test suite | Command | Results |
|---|---|---|
| All component tests | gradlew.bat componentTests --continue | build/reports/tests/componentTests/index.html |
| Individual test | gradlew.bat componentTests --tests TestClassName | build/reports/tests/componentTests/index.html |
To generate coverage data:
gradlew.bat componentTests jacocoReport
The report can be found in build/reports/jacoco/jacocoReport/.
Frontend tests should follow the format: "<function-name>: should ... when/if ..."
it("hasSection: should return false when there are no sections in the course");
Backend tests should follow the format: test<functionName>_<scenario>_<outcome>
public void testGetComment_commentDoesNotExist_returnsNull()
public void testCreateComment_commentDoesNotExist_success()
public void testCreateComment_commentAlreadyExists_throwsEntityAlreadyExistsException()
Frontend: Use the builder in src/web/test-helpers/generic-builder.ts to include only relevant details:
const instructorModelBuilder = createBuilder<InstructorListInfoTableRowModel>({
email: "instructor@gmail.com",
name: "Instructor",
hasSubmittedSession: false,
isSelected: false,
});
it("isAllInstructorsSelected: should return false if at least one instructor is not selected", () => {
component.instructorListInfoTableRowModels = [
instructorModelBuilder.isSelected(true).build(),
instructorModelBuilder.isSelected(false).build(),
];
expect(component.isAllInstructorsSelected).toBeFalsy();
});
Backend: Use the getTypicalX functions in BaseTestCase:
Account account = getTypicalAccount();
account.setEmail("newemail@teammates.com");
Student student = getTypicalStudent();
student.setName("New Student Name");
Snapshot testing compares large expected outputs (e.g. rendered HTML, email content, CSV files) against stored snapshots. It runs in two modes:
Frontend: Auto-update mode is activated by pressing u in Jest watch mode.
Backend: Auto-update mode is activated by setting test.snapshot.update=true in test.properties.
A few things to keep in mind:
E2E tests are black-box tests that simulate user workflows on the fully built application. Accessibility tests are a subset of E2E tests that check for WCAG compliance using axe-core.
teammates.e2e, configured in src/e2e/resources/testng-e2e.xml.teammates.e2e.cases.axe.Before running E2E tests:
npm run build
./gradlew serverRun
test.app.frontend.url=http://localhost:4200
test.app.backend.url=http://localhost:8080
Then start both the frontend and backend servers.
npm run start
./gradlew serverRun
npm run build
gradlew.bat serverRun
test.app.frontend.url=http://localhost:4200
test.app.backend.url=http://localhost:8080
Then start both the frontend and backend servers.
npm run start
gradlew.bat serverRun
Configure src/e2e/resources/test.properties:
test.selenium.browser)test.app.frontend.url, test.app.backend.url)Download the appropriate browser driver (see below).
| Test suite | Command | Results |
|---|---|---|
| All E2E tests | ./gradlew e2eTests | build/reports/e2e-test-try-{n}/index.html |
| Individual test | ./gradlew e2eTestTry1 --tests TestClassName | build/reports/e2e-test-try-1/index.html |
| Accessibility tests | ./gradlew axeTests | build/reports/axe-test/index.html |
| Individual accessibility test | ./gradlew axeTests --tests TestClassName | build/reports/axe-test/index.html |
| Test suite | Command | Results |
|---|---|---|
| All E2E tests | gradlew.bat e2eTests | build/reports/e2e-test-try-{n}/index.html |
| Individual test | gradlew.bat e2eTestTry1 --tests TestClassName | build/reports/e2e-test-try-1/index.html |
| Accessibility tests | gradlew.bat axeTests | build/reports/axe-test/index.html |
| Individual accessibility test | gradlew.bat axeTests --tests TestClassName | build/reports/axe-test/index.html |
Some tests may fail intermittently due to timing issues — rerun them until they pass.
src/e2e/resources/test.properties as instructed in its comments. You will need a legitimate Gmail account for testing.src/e2e/resources/gmail-api/client_secret.json.EmailAccountTest to confirm the setup works.Each test case should reflect a user workflow. For each page:
All E2E test classes inherit from BaseE2ETestCase. Use BackDoor to verify database state without going through the UI.
TEAMMATES uses the Page Object Pattern to make tests resilient to UI changes. Each page is represented by a page object class that exposes page functionality as methods, hiding the underlying UI elements.
AppPage.searchForInstructor over exposing lower-level methods like fillSearchBox and clickSearchButton.