1
0
Fork 0
mirror of https://codeberg.org/beerbrawl/beerbrawl.git synced 2024-09-23 09:40:52 +02:00

Merge branch 'test/#18/e2e' into 'development'

test(#18): add e2e tests for qualification match functionality

See merge request 2024ss-se-pr-group/24ss-se-pr-qse-11!69
This commit is contained in:
Christoph Heiss 2024-05-30 21:20:58 +00:00
commit 649afb8983
15 changed files with 142 additions and 29 deletions

View file

@ -6,6 +6,7 @@ import at.ac.tuwien.sepr.groupphase.backend.entity.Tournament;
import at.ac.tuwien.sepr.groupphase.backend.repository.TeamRepository;
import at.ac.tuwien.sepr.groupphase.backend.repository.TournamentRepository;
import at.ac.tuwien.sepr.groupphase.backend.repository.UserRepository;
import at.ac.tuwien.sepr.groupphase.backend.service.TournamentService;
import jakarta.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -15,6 +16,8 @@ import org.springframework.stereotype.Component;
import java.lang.invoke.MethodHandles;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.List;
import java.util.stream.IntStream;
@Profile("generateData")
@ -28,14 +31,17 @@ public class TestDataGenerator {
private final UserRepository userRepository;
private final TeamRepository teamRepository;
private final TournamentRepository tournamentRepository;
private final TournamentService tournamentService;
public TestDataGenerator(
TournamentRepository tournamentRepository,
TournamentService tournamentService,
UserRepository userRepository,
TeamRepository teamRepository,
PasswordEncoder passwordEncoder
) {
this.tournamentRepository = tournamentRepository;
this.tournamentService = tournamentService;
this.userRepository = userRepository;
this.teamRepository = teamRepository;
this.passwordEncoder = passwordEncoder;
@ -54,22 +60,37 @@ public class TestDataGenerator {
userRepository.save(newUser);
}
public void generateTestTournament() {
public void generateTestTournaments() {
LOGGER.debug("generating TEST_TOURNAMENT tournament");
final var tournament = new Tournament("TEST_TOURNAMENT", LocalDateTime.now().plusDays(100), 64L,
final var tournament = new Tournament(
"TEST_TOURNAMENT", currentUtcTime().plusDays(7), 64L,
"TEST_TOURNAMENT_DESCRIPTION", userRepository.findByUsername(TEST_USER));
tournamentRepository.save(tournament);
final var tournament2 = new Tournament(
"TEST_TOURNAMENT2", currentUtcTime().plusDays(7), 32L,
"TEST_TOURNAMENT2_DESCRIPTION", userRepository.findByUsername(TEST_USER));
final var teams = IntStream.range(0, 64)
tournamentRepository.saveAllAndFlush(List.of(tournament, tournament2));
final var teams1 = IntStream.range(0, 64)
.mapToObj(i -> new Team("Test Team #%02d".formatted(i), tournament))
.toList();
teamRepository.saveAllAndFlush(teams);
teamRepository.saveAllAndFlush(teams1);
var teams2 = IntStream.range(0, 32)
.mapToObj(i -> new Team("Test Team #%02d".formatted(i), tournament2))
.toList();
teams2 = teamRepository.saveAllAndFlush(teams2);
teams2.forEach(t -> tournamentService.markTeamAsReady(tournament2.getId(), t.getId()));
}
@PostConstruct
private void generateTestData() {
generateTestUser();
generateTestTournament();
generateTestTournaments();
}
private static LocalDateTime currentUtcTime() {
return LocalDateTime.now(ZoneOffset.UTC);
}
}

View file

@ -5,6 +5,7 @@ import at.ac.tuwien.sepr.groupphase.backend.repository.TeamRepository;
import at.ac.tuwien.sepr.groupphase.backend.repository.TournamentRepository;
import at.ac.tuwien.sepr.groupphase.backend.repository.UserRepository;
import at.ac.tuwien.sepr.groupphase.backend.service.TournamentService;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
@ -21,6 +22,8 @@ public abstract class TestTournamentData {
@Autowired
private TournamentRepository tournamentRepository;
@Autowired
private TournamentService tournamentService;
@Autowired
private TeamRepository teamRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@ -28,10 +31,10 @@ public abstract class TestTournamentData {
@BeforeEach
public void generateTestUser() {
var dataGenerator = new TestDataGenerator(
this.tournamentRepository, this.userRepository,
this.teamRepository, this.passwordEncoder);
this.tournamentRepository, this.tournamentService,
this.userRepository, this.teamRepository, this.passwordEncoder);
dataGenerator.generateTestUser();
dataGenerator.generateTestTournament();
dataGenerator.generateTestTournaments();
}
@AfterEach

View file

@ -5,6 +5,7 @@ import at.ac.tuwien.sepr.groupphase.backend.repository.TeamRepository;
import at.ac.tuwien.sepr.groupphase.backend.repository.TournamentRepository;
import at.ac.tuwien.sepr.groupphase.backend.repository.UserRepository;
import at.ac.tuwien.sepr.groupphase.backend.service.TournamentService;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
@ -21,16 +22,18 @@ public abstract class TestUserData {
@Autowired
private TournamentRepository tournamentRepository;
@Autowired
private TournamentService tournamentService;
@Autowired
private TeamRepository teamRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@BeforeEach
public void generateTestUser() {
var userGenerator = new TestDataGenerator(
this.tournamentRepository, this.userRepository,
this.teamRepository, this.passwordEncoder);
userGenerator.generateTestUser();
var dataGenerator = new TestDataGenerator(
this.tournamentRepository, this.tournamentService,
this.userRepository, this.teamRepository, this.passwordEncoder);
dataGenerator.generateTestUser();
}
@AfterEach

View file

@ -552,9 +552,9 @@ public class TournamentEndpointTest extends TestTournamentData implements TestDa
assertThat(tournaments)
.isNotNull()
.hasSize(1)
.hasSize(2)
.extracting("name")
.containsExactly(tournament.getName());
.contains(tournament.getName());
final var listDto = tournaments[0];
final var createDto = new TournamentUpdateTeamDto("baz");
@ -585,9 +585,9 @@ public class TournamentEndpointTest extends TestTournamentData implements TestDa
assertThat(tournaments)
.isNotNull()
.hasSize(1)
.hasSize(2)
.extracting("name")
.containsExactly(tournament.getName());
.contains(tournament.getName());
final var listDto = tournaments[0];
final var createDto = new TournamentUpdateTeamDto("baz");

View file

@ -232,7 +232,7 @@ public class TournamentServiceTest extends TestUserData implements TestData {
private Tournament generateTouramentWithQualificationMatches() {
var tournament = new Tournament(
"testname", currentUtcTime().plusMinutes(1), 64L, "testdescription",
"testname", currentUtcTime().plusDays(7), 64L, "testdescription",
userRepository.findByUsername(TEST_USER));
tournamentService.create(tournament, TEST_USER);

View file

@ -56,7 +56,7 @@ context('Delete Beer Pong Table', () => {
cy.get('[data-cy="beer-pong-tables-list-item"]').first().as('firstBeerPongTable');
cy.get('@firstBeerPongTable').find('[data-cy="delete-beer-pong-table-btn"]').click();
cy.get('[data-cy="confirm-delete-btn"]').click();
cy.get('[data-cy="confirm-dialog-btn"]').click();
cy.wait('@deleteBeerPongTable');
cy.wait('@getBeerPongTables');
@ -85,7 +85,7 @@ context('Delete Beer Pong Table', () => {
cy.get('[data-cy="beer-pong-tables-list-item"]').first().as('firstBeerPongTable');
cy.get('@firstBeerPongTable').find('[data-cy="delete-beer-pong-table-btn"]').click();
cy.get('[data-cy="cancel-delete-btn"]').click();
cy.get('[data-cy="cancel-dialog-btn"]').click();
cy.get('@firstBeerPongTable').should('exist');
cy.get('[data-cy="beer-pong-tables-list-item"]').should('have.length', 3);

View file

@ -0,0 +1,46 @@
import * as cypress from 'cypress';
context('update qualification match results', () => {
beforeEach(() => {
cy.loginTestUser();
cy.wait(2000);
});
it('should be able to mark teams as ready', () => {
cy.fixture('settings').then(settings => {
cy.visit(`http://${settings.baseUrl}/#/tournaments/1/qualification-phase`);
cy.get('app-header-card').contains('Qualification Round').should('exist');
cy.get('app-tournament-score-table')
.find('tbody')
.find('button[aria-label="mark team as ready"]')
.should('have.length', 64)
.first()
.click();
cy.get('button[data-cy="confirm-dialog-btn"]').click();
cy.wait(4000);
cy.get('app-tournament-score-table')
.find('tbody')
.find('button[aria-label="mark team as ready"]')
.should('have.length', 63);
});
});
it('should be able to generate qualification matches', () => {
cy.fixture('settings').then(settings => {
cy.visit(`http://${settings.baseUrl}/#/tournaments/2/qualification-phase`);
// for tournament2, all teams should already be "ready"
cy.get('app-header-card').contains('Qualification Round').should('exist');
cy.get('app-tournament-score-table')
.find('tbody')
.find('button[aria-label="mark team as ready"]')
.should('have.length', 0);
cy.get('[data-cy="generate-qualification-matches-btn"]').click();
cy.get('button[data-cy="confirm-dialog-btn"]').click();
});
});
});

View file

@ -52,7 +52,7 @@ context('Delete Tournament', () => {
cy.get('[data-cy="tournaments-list-item"]').first().as('firstTournament');
cy.get('@firstTournament').find('[data-cy="delete-tournament-btn"]').click();
cy.get('[data-cy="confirm-delete-btn"]').click();
cy.get('[data-cy="confirm-dialog-btn"]').click();
cy.wait('@deleteTournament');
cy.wait('@getTournaments');
@ -80,7 +80,7 @@ context('Delete Tournament', () => {
cy.get('[data-cy="tournaments-list-item"]').first().as('firstTournament');
cy.get('@firstTournament').find('[data-cy="delete-tournament-btn"]').click();
cy.get('[data-cy="cancel-delete-btn"]').click();
cy.get('[data-cy="cancel-dialog-btn"]').click();
// Ensure the tournament is still present
cy.get('@firstTournament').should('exist');

16
e2e/package-lock.json generated
View file

@ -15,7 +15,8 @@
"mocha-junit-reporter": "2.2.1"
},
"devDependencies": {
"prettier": "^3.2.5"
"prettier": "^3.2.5",
"typescript": "^5.4.5"
}
},
"node_modules/@colors/colors": {
@ -2796,6 +2797,19 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/typescript": {
"version": "5.4.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
"integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",

View file

@ -11,7 +11,8 @@
"mocha-junit-reporter": "2.2.1"
},
"devDependencies": {
"prettier": "^3.2.5"
"prettier": "^3.2.5",
"typescript": "^5.4.5"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",

20
e2e/tsconfig.json Normal file
View file

@ -0,0 +1,20 @@
{
"compileOnSave": false,
"compilerOptions": {
"downlevelIteration": true,
"importHelpers": true,
"outDir": "./dist/out-tsc",
"declaration": false,
"module": "es2022",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es2022",
"typeRoots": ["node_modules/@types"],
"useDefineForClassFields": false,
"strict": true,
"lib": ["es2018", "dom"],
"types": ["cypress", "node"]
},
"include": ["**/*.ts"]
}

View file

@ -8,7 +8,7 @@
<div mat-dialog-actions>
<button
mat-flat-button
data-cy="cancel-delete-btn"
data-cy="cancel-dialog-btn"
color="warn"
aria-label="cancel-action button"
[mat-dialog-close]="false"
@ -18,7 +18,7 @@
</button>
<button
mat-flat-button
data-cy="confirm-delete-btn"
data-cy="confirm-dialog-btn"
color="primary"
aria-label="ok button"
[mat-dialog-close]="true"

View file

@ -12,7 +12,7 @@
<div class="form-actions" mat-dialog-actions>
<button
mat-flat-button
data-cy="cancel-delete-btn"
data-cy="cancel-btn"
color="warn"
aria-label="Cancel updating team"
mat-dialog-close

View file

@ -24,7 +24,7 @@
<div class="form-actions" mat-dialog-actions>
<button
mat-flat-button
data-cy="cancel-delete-btn"
data-cy="cancel-btn"
color="warn"
aria-label="Cancel entering match results"
mat-dialog-close

View file

@ -16,7 +16,12 @@
<div class="no-matches-container">
<h1>Its empty here</h1>
<h2>There are no matches generated for the qualification phase yet.</h2>
<button (click)="generateQualificationMatches()" mat-flat-button [color]="'primary'">
<button
(click)="generateQualificationMatches()"
mat-flat-button
[color]="'primary'"
data-cy="generate-qualification-matches-btn"
>
<mat-icon>settings_suggest</mat-icon>
Generate matches
</button>