Commit 68e69795 authored by Viktor Boev's avatar Viktor Boev
Browse files

add component test (with mocking)

parent 27604b9f
Showing with 120 additions and 31 deletions
+120 -31
import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing'
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'
import { LoginComponent } from './login.component';
import { AuthService } from 'src/app/services/auth.service';
import { Router } from '@angular/router';
import { LoginRequest } from 'src/app/models/requests/login-request';
import { LoginResponse } from 'src/app/models/responses/login-response';
import { FormsModule } from '@angular/forms';
describe('LoginComponent', () => {
let authService: AuthService;
let httpTestingController: HttpTestingController;
let mockRouter: any;
let component: LoginComponent;
let fixture: ComponentFixture<LoginComponent>
beforeEach(() => {
mockRouter = {
navigate: jasmine.createSpy('navigate') // Create a spy for the router.navigate method
};
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [LoginComponent]
}).compileComponents;
declarations: [LoginComponent],
imports: [HttpClientTestingModule, FormsModule],
providers: [AuthService, {provide: Router, useValue: mockRouter}],
});
authService = TestBed.inject(AuthService);
httpTestingController = TestBed.inject(HttpTestingController);
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
afterEach(() => {
httpTestingController.verify();
});
it ('create login', () => {
const fixture = TestBed.createComponent(LoginComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
expect(component).toBeTruthy();
})
it('successful login', () => {
const username = fixture.nativeElement.querySelector('#username');
const password = fixture.nativeElement.querySelector('#password');
username.value = 'ivana';
username.dispatchEvent(new Event('input'));
password.value = '123';
password.dispatchEvent(new Event('input'));
fixture.detectChanges();
const loginResponse: LoginResponse = {
username: 'ivana',
role: 'ROLE_STUDENT',
jwt: '2sfsf',
id: 1
};
const mySpy = spyOn(localStorage, 'setItem');
component.onSubmit();
const req = httpTestingController.expectOne('http://localhost:8080/auth/login');
req.flush(loginResponse);
expect(mySpy).toHaveBeenCalledWith('jwt', '2sfsf');
expect(mySpy).toHaveBeenCalledWith('role', 'ROLE_STUDENT');
expect(mySpy).toHaveBeenCalledWith('id', '1');
expect(mySpy).toHaveBeenCalledWith('username', 'ivana');
expect(mockRouter.navigate).toHaveBeenCalledWith(['/homepage']);
});
});
\ No newline at end of file
......@@ -8,11 +8,12 @@ import project.utilities.dtos.course.CourseCreateRequest;
import project.utilities.dtos.course.CourseDto;
import project.utilities.dtos.grade.AddGrade;
import project.utilities.dtos.grade.GradeDto;
import project.utilities.dtos.mixed_requests.CourseNameStudentIdRequest;
import project.utilities.dtos.mixed_requests.CourseNameTeacherIdRequest;
import project.utilities.dtos.mixed_requests.CourseNameStudentUsernameRequest;
import project.utilities.dtos.mixed_requests.CourseNameTeacherUsernameRequest;
import project.utilities.dtos.mixed_responses.*;
import project.utilities.dtos.student.StudentCourseDto;
import project.utilities.services.course.CourseService;
import project.utilities.services.user.UserService;
import java.util.List;
......@@ -20,9 +21,12 @@ import java.util.List;
@RequestMapping("/courses")
public class CourseController {
private final CourseService courseService;
private final UserService userService;
public CourseController(CourseService courseService) {
public CourseController(CourseService courseService, UserService userService) {
this.courseService = courseService;
this.userService = userService;
}
@PostMapping("/create")
......@@ -33,17 +37,19 @@ public class CourseController {
}
@PatchMapping("/add-teacher")
public ResponseEntity<CourseTeacherResponse> addTeacherToCourse(@Valid @RequestBody CourseNameTeacherIdRequest input) {
public ResponseEntity<CourseTeacherResponse> addTeacherToCourse(@Valid @RequestBody CourseNameTeacherUsernameRequest input) {
long teacherId = this.userService.getId(input.teacherUsername());
CourseTeacherResponse response =
this.courseService.addTeacherToCourse(input.courseName(), input.teacherId());
this.courseService.addTeacherToCourse(input.courseName(), teacherId);
return ResponseEntity.status(HttpStatus.CREATED)
.body(response);
}
@PatchMapping("/add-student")
public ResponseEntity<CourseStudentResponse> addStudentInCourse(@Valid @RequestBody CourseNameStudentIdRequest input) {
public ResponseEntity<CourseStudentResponse> addStudentInCourse(@Valid @RequestBody CourseNameStudentUsernameRequest input) {
long studentId = this.userService.getId(input.studentUsername());
CourseStudentResponse response =
this.courseService.addStudentToCourse(input.courseName(), input.studentId());
this.courseService.addStudentToCourse(input.courseName(), studentId);
return ResponseEntity.status(HttpStatus.CREATED)
.body(response);
}
......
......@@ -3,10 +3,7 @@ package project.utilities.controllers;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import project.utilities.dtos.student.StudentUserDto;
import project.utilities.dtos.teacher.TeacherUserDto;
import project.utilities.services.user.UserService;
......@@ -32,4 +29,10 @@ public class UserController {
return ResponseEntity.status(HttpStatus.OK)
.body(response);
}
@DeleteMapping("/delete/{username}")
public ResponseEntity<String> deleteUser(@PathVariable String username) {
this.userService.deleteUser(username);
return ResponseEntity.status(HttpStatus.OK).body("User: {" + username + "} is deleted");
}
}
package project.utilities.dtos.mixed_requests;
public record CourseNameStudentIdRequest(String courseName, Long studentId) {
import lombok.NonNull;
public record CourseNameStudentUsernameRequest(@NonNull String courseName, @NonNull String studentUsername) {
}
package project.utilities.dtos.mixed_requests;
public record CourseNameTeacherIdRequest(String courseName, Long teacherId) {
import lombok.NonNull;
public record CourseNameTeacherUsernameRequest(@NonNull String courseName, @NonNull String teacherUsername) {
}
package project.utilities.dtos.mixed_requests;
import lombok.NonNull;
import jakarta.validation.Valid;
import project.utilities.dtos.student.StudentCreateRequest;
import project.utilities.dtos.user.UserCreateRequest;
public record UserStudentRequest(
@NonNull UserCreateRequest userRequest,
@NonNull StudentCreateRequest studentRequest
@Valid UserCreateRequest userRequest,
@Valid StudentCreateRequest studentRequest
) {
}
......@@ -3,6 +3,7 @@ package project.utilities.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import project.utilities.entities.Course;
import project.utilities.entities.Student;
import java.util.List;
import java.util.Optional;
......@@ -11,9 +12,11 @@ public interface CourseRepository extends JpaRepository<Course, Long> {
@Query("SELECT t FROM Course t ORDER BY t.name")
List<Course> findAllOrderByNameDesc();
@Query("SELECT t FROM Course t WHERE t.name LIKE CONCAT('%',?1,'%')")
List<Course> findAllFilteredByName(String filter);
List<Course> findAllByNameContainingIgnoreCase(String filter);
@Query("SELECT t FROM Course t WHERE ?1 = t.name")
Optional<Course> findByCourseName(String courseName);
@Query("SELECT s FROM Student s JOIN s.assignedCourses c WHERE c.name = ?1 AND LOWER(s.name) LIKE LOWER(CONCAT('%', ?2, '%'))")
List<Student> findStudentsByNameForCourse(String courseName, String studentName);
}
......@@ -112,7 +112,8 @@ public class SecurityConfig {
"/courses/add-teacher",
"/courses/remove-teacher/{courseId}",
"/auth/register/**",
"/admin/change/**"
"/admin/change/**",
"/user/delete/{username}"
).hasRole(ROLE_ADMIN)
.anyRequest().authenticated())
.sessionManagement(
......
......@@ -85,6 +85,7 @@ public class CourseService {
Course course = handleCourseFindByName(courseName);
return course.getId();
}
public CourseStudentResponse addStudentToCourse(String courseName, long studentId) {
Course course = handleCourseFindByName(courseName);
Student student = this.studentService.findById(studentId);
......@@ -153,9 +154,9 @@ public class CourseService {
List<StudentGradeDto> output = new ArrayList<>();
Course course = handleCourseFindByName(courseName);
course.getEnrolledStudents().stream()
.filter(student -> student.getName().toLowerCase()
.contains(context.toLowerCase()))
this.repository.findStudentsByNameForCourse(
courseName, context
)
.forEach(s -> output.add(new StudentGradeDto(
studentMapper.toStudentDto(s),
this.studentService.getStudentCourseDto(s, course).average()))
......@@ -198,7 +199,7 @@ public class CourseService {
}
public List<CourseTeacherStudentsResponse> filterCoursesByName(String context) {
return this.repository.findAllFilteredByName(context).stream()
return this.repository.findAllByNameContainingIgnoreCase(context).stream()
.map(this::getTeacherStudents)
.toList();
}
......
......@@ -175,6 +175,20 @@ public class UserService implements UserDetailsService {
}
}
public void deleteUser(String username) {
User user = handleUserFindByUsername(username);
if (user.getRole() == Role.ROLE_TEACHER) {
this.removeTeacher(user);
this.repository.delete(user);
return;
}
if (user.getRole() == Role.ROLE_STUDENT) {
this.removeStudent(user);
this.repository.delete(user);
}
}
@Transactional
private String removeTeacher(User user) {
Teacher teacher = user.getTeacher()
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment