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:
commit
649afb8983
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
46
e2e/cypress/e2e/qualification-matches.cy.ts
Normal file
46
e2e/cypress/e2e/qualification-matches.cy.ts
Normal 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();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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
16
e2e/package-lock.json
generated
|
@ -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",
|
||||
|
|
|
@ -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
20
e2e/tsconfig.json
Normal 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"]
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue