From 063353ab71aad46eb498eb8d9be4a9ab3a644a8a Mon Sep 17 00:00:00 2001 From: Asli Aykan Date: Mon, 2 Dec 2024 22:26:29 +0100 Subject: [PATCH 01/13] removed unnecessary classes, added inject and input-output signals --- .../answer-post/answer-post.component.html | 4 +- .../webapp/app/shared/metis/metis.module.ts | 9 +- .../app/shared/metis/post/post.component.html | 2 +- .../post-footer/post-footer.component.html | 14 +- .../post-footer/post-footer.component.ts | 62 ++---- .../posting-footer.directive.ts | 8 - .../answer-post-header.component.html | 41 ---- .../answer-post-header.component.ts | 31 --- .../post-header/post-header.component.ts | 46 ---- ...ent.html => posting-header.component.html} | 24 +- .../posting-header.component.ts} | 90 ++++++-- .../shared/metis/post/post.component.spec.ts | 4 +- .../post-footer/post-footer.component.spec.ts | 82 ++++--- .../answer-post-header.component.spec.ts | 106 --------- .../post-header/post-header.component.spec.ts | 89 -------- .../posting-header.component.spec.ts | 208 ++++++++++++++++++ 16 files changed, 377 insertions(+), 443 deletions(-) delete mode 100644 src/main/webapp/app/shared/metis/posting-footer/posting-footer.directive.ts delete mode 100644 src/main/webapp/app/shared/metis/posting-header/answer-post-header/answer-post-header.component.html delete mode 100644 src/main/webapp/app/shared/metis/posting-header/answer-post-header/answer-post-header.component.ts delete mode 100644 src/main/webapp/app/shared/metis/posting-header/post-header/post-header.component.ts rename src/main/webapp/app/shared/metis/posting-header/post-header/{post-header.component.html => posting-header.component.html} (70%) rename src/main/webapp/app/shared/metis/posting-header/{posting-header.directive.ts => post-header/posting-header.component.ts} (57%) delete mode 100644 src/test/javascript/spec/component/shared/metis/postings-header/answer-post-header/answer-post-header.component.spec.ts delete mode 100644 src/test/javascript/spec/component/shared/metis/postings-header/post-header/post-header.component.spec.ts create mode 100644 src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts diff --git a/src/main/webapp/app/shared/metis/answer-post/answer-post.component.html b/src/main/webapp/app/shared/metis/answer-post/answer-post.component.html index 8a703757ecfc..7a360f5aab84 100644 --- a/src/main/webapp/app/shared/metis/answer-post/answer-post.component.html +++ b/src/main/webapp/app/shared/metis/answer-post/answer-post.component.html @@ -9,9 +9,9 @@ } @if (!isConsecutive()) {
- -
{{ @@ -15,17 +15,17 @@ @for (group of groupedAnswerPosts; track trackGroupByFn($index, group)) { @for (answerPost of group.posts; track trackPostByFn($index, answerPost)) { } } @@ -38,6 +38,6 @@ #createAnswerPostModal [posting]="createdAnswerPost" [createEditAnswerPostContainerRef]="containerRef" - (onCreate)="createdAnswerPost = createEmptyAnswerPost(); showAnswers = true" + (onCreate)="createdAnswerPost = createEmptyAnswerPost(); showAnswers()" />
diff --git a/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts b/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts index 5808a9b342ba..fb7cfb890392 100644 --- a/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts +++ b/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts @@ -1,18 +1,4 @@ -import { - AfterContentChecked, - ChangeDetectorRef, - Component, - EventEmitter, - Input, - OnChanges, - OnDestroy, - OnInit, - Output, - SimpleChanges, - ViewChild, - ViewContainerRef, -} from '@angular/core'; -import { PostingFooterDirective } from 'app/shared/metis/posting-footer/posting-footer.directive'; +import { AfterContentChecked, ChangeDetectorRef, Component, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewChild, ViewContainerRef, inject, input, output } from '@angular/core'; import { Post } from 'app/entities/metis/post.model'; import { MetisService } from 'app/shared/metis/metis.service'; import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; @@ -20,6 +6,7 @@ import { AnswerPostCreateEditModalComponent } from 'app/shared/metis/posting-cre import { AnswerPost } from 'app/entities/metis/answer-post.model'; import dayjs from 'dayjs/esm'; import { User } from 'app/core/user/user.model'; +import { Posting } from 'app/entities/metis/posting.model'; interface PostGroup { author: User | undefined; @@ -31,19 +18,22 @@ interface PostGroup { templateUrl: './post-footer.component.html', styleUrls: ['./post-footer.component.scss'], }) -export class PostFooterComponent extends PostingFooterDirective implements OnInit, OnDestroy, AfterContentChecked, OnChanges { - @Input() lastReadDate?: dayjs.Dayjs; - @Input() readOnlyMode = false; - @Input() previewMode = false; - @Input() modalRef?: NgbModalRef; - @Input() hasChannelModerationRights = false; - @Input() showAnswers = false; - @Input() isCommunicationPage = false; - @Input() sortedAnswerPosts: AnswerPost[] = []; - - @Output() openThread = new EventEmitter(); - @Output() userReferenceClicked = new EventEmitter(); - @Output() channelReferenceClicked = new EventEmitter(); +export class PostFooterComponent implements OnInit, OnDestroy, AfterContentChecked, OnChanges { + lastReadDate = input(); + readOnlyMode = input(false); + previewMode = input(false); + modalRef = input(); + hasChannelModerationRights = input(false); + showAnswers = input(false); + isCommunicationPage = input(false); + sortedAnswerPosts = input([]); + isThreadSidebar = input(false); + posting = input(); + + // Output Signals + openThread = output(); + userReferenceClicked = output(); + channelReferenceClicked = output(); @ViewChild(AnswerPostCreateEditModalComponent) answerPostCreateEditModal?: AnswerPostCreateEditModalComponent; @ViewChild('createEditAnswerPostContainer', { read: ViewContainerRef }) containerRef!: ViewContainerRef; @@ -54,12 +44,8 @@ export class PostFooterComponent extends PostingFooterDirective implements courseId!: number; groupedAnswerPosts: PostGroup[] = []; - constructor( - private metisService: MetisService, - protected changeDetector: ChangeDetectorRef, - ) { - super(); - } + protected metisService: MetisService = inject(MetisService); + protected changeDetector: ChangeDetectorRef = inject(ChangeDetectorRef); ngOnInit(): void { this.courseId = this.metisService.getCourse().id!; @@ -94,18 +80,18 @@ export class PostFooterComponent extends PostingFooterDirective implements createEmptyAnswerPost(): AnswerPost { const answerPost = new AnswerPost(); answerPost.content = ''; - answerPost.post = this.posting; + answerPost.post = this.posting(); answerPost.resolvesPost = this.isAtLeastTutorInCourse; return answerPost; } groupAnswerPosts(): void { - if (!this.sortedAnswerPosts || this.sortedAnswerPosts.length === 0) { + if (!this.sortedAnswerPosts() || this.sortedAnswerPosts().length === 0) { this.groupedAnswerPosts = []; return; } - this.sortedAnswerPosts = this.sortedAnswerPosts + const sortedAnswerPosts = this.sortedAnswerPosts() .slice() .reverse() .map((post) => { @@ -113,7 +99,7 @@ export class PostFooterComponent extends PostingFooterDirective implements return post; }); - const sortedPosts = this.sortedAnswerPosts.sort((a, b) => { + const sortedPosts = sortedAnswerPosts.sort((a, b) => { const aDate = (a as any).creationDateDayjs; const bDate = (b as any).creationDateDayjs; return aDate?.valueOf() - bDate?.valueOf(); diff --git a/src/main/webapp/app/shared/metis/posting-footer/posting-footer.directive.ts b/src/main/webapp/app/shared/metis/posting-footer/posting-footer.directive.ts deleted file mode 100644 index 4db2a7c56499..000000000000 --- a/src/main/webapp/app/shared/metis/posting-footer/posting-footer.directive.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Directive, Input } from '@angular/core'; -import { Posting } from 'app/entities/metis/posting.model'; - -@Directive() -export abstract class PostingFooterDirective { - @Input() posting: T; - @Input() isThreadSidebar: boolean; -} diff --git a/src/main/webapp/app/shared/metis/posting-header/answer-post-header/answer-post-header.component.html b/src/main/webapp/app/shared/metis/posting-header/answer-post-header/answer-post-header.component.html deleted file mode 100644 index a03fb20cced3..000000000000 --- a/src/main/webapp/app/shared/metis/posting-header/answer-post-header/answer-post-header.component.html +++ /dev/null @@ -1,41 +0,0 @@ -
- -
diff --git a/src/main/webapp/app/shared/metis/posting-header/answer-post-header/answer-post-header.component.ts b/src/main/webapp/app/shared/metis/posting-header/answer-post-header/answer-post-header.component.ts deleted file mode 100644 index 45bd9775fd06..000000000000 --- a/src/main/webapp/app/shared/metis/posting-header/answer-post-header/answer-post-header.component.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core'; -import { AnswerPost } from 'app/entities/metis/answer-post.model'; -import { PostingHeaderDirective } from 'app/shared/metis/posting-header/posting-header.directive'; -import { faCheck, faPencilAlt } from '@fortawesome/free-solid-svg-icons'; -import dayjs from 'dayjs/esm'; - -@Component({ - selector: 'jhi-answer-post-header', - templateUrl: './answer-post-header.component.html', - styleUrls: ['../../metis.component.scss'], -}) -export class AnswerPostHeaderComponent extends PostingHeaderDirective implements OnInit, OnChanges { - @Input() - isReadOnlyMode = false; - - @Input() lastReadDate?: dayjs.Dayjs; - @Output() openPostingCreateEditModal = new EventEmitter(); - - // Icons - readonly faCheck = faCheck; - readonly faPencilAlt = faPencilAlt; - - ngOnInit() { - super.ngOnInit(); - } - - ngOnChanges() { - this.setUserProperties(); - this.setUserAuthorityIconAndTooltip(); - } -} diff --git a/src/main/webapp/app/shared/metis/posting-header/post-header/post-header.component.ts b/src/main/webapp/app/shared/metis/posting-header/post-header/post-header.component.ts deleted file mode 100644 index 2d45812fe382..000000000000 --- a/src/main/webapp/app/shared/metis/posting-header/post-header/post-header.component.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Component, Input, OnChanges, OnDestroy, OnInit, ViewChild } from '@angular/core'; -import { Post } from 'app/entities/metis/post.model'; -import { PostingHeaderDirective } from 'app/shared/metis/posting-header/posting-header.directive'; -import { PostCreateEditModalComponent } from 'app/shared/metis/posting-create-edit-modal/post-create-edit-modal/post-create-edit-modal.component'; -import { faCheckSquare, faPencilAlt } from '@fortawesome/free-solid-svg-icons'; -import dayjs from 'dayjs/esm'; -import { CachingStrategy } from 'app/shared/image/secured-image.component'; - -@Component({ - selector: 'jhi-post-header', - templateUrl: './post-header.component.html', - styleUrls: ['../../metis.component.scss'], -}) -export class PostHeaderComponent extends PostingHeaderDirective implements OnInit, OnDestroy, OnChanges { - @Input() - readOnlyMode = false; - @Input() lastReadDate?: dayjs.Dayjs; - @Input() previewMode: boolean; - @ViewChild(PostCreateEditModalComponent) postCreateEditModal?: PostCreateEditModalComponent; - isAtLeastInstructorInCourse: boolean; - - // Icons - readonly faPencilAlt = faPencilAlt; - readonly faCheckSquare = faCheckSquare; - - ngOnInit() { - super.ngOnInit(); - } - - /** - * on changes: re-evaluates authority roles - */ - ngOnChanges() { - this.setUserProperties(); - this.setUserAuthorityIconAndTooltip(); - } - - /** - * on leaving the page, the modal should be closed - */ - ngOnDestroy(): void { - this.postCreateEditModal?.modalRef?.close(); - } - - protected readonly CachingStrategy = CachingStrategy; -} diff --git a/src/main/webapp/app/shared/metis/posting-header/post-header/post-header.component.html b/src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.html similarity index 70% rename from src/main/webapp/app/shared/metis/posting-header/post-header/post-header.component.html rename to src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.html index 1bce282adaed..d8630a86ad89 100644 --- a/src/main/webapp/app/shared/metis/posting-header/post-header/post-header.component.html +++ b/src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.html @@ -1,6 +1,6 @@
diff --git a/src/main/webapp/app/shared/metis/posting-header/posting-header.directive.ts b/src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.ts similarity index 57% rename from src/main/webapp/app/shared/metis/posting-header/posting-header.directive.ts rename to src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.ts index 8868f60124c1..437619640f7c 100644 --- a/src/main/webapp/app/shared/metis/posting-header/posting-header.directive.ts +++ b/src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.ts @@ -1,25 +1,37 @@ -import { Posting } from 'app/entities/metis/posting.model'; -import { Directive, EventEmitter, Input, OnInit, Output, inject, input } from '@angular/core'; +import { Component, OnChanges, OnDestroy, OnInit, ViewChild, inject, input, output } from '@angular/core'; +import { PostCreateEditModalComponent } from 'app/shared/metis/posting-create-edit-modal/post-create-edit-modal/post-create-edit-modal.component'; +import { faCheckSquare, faPencilAlt } from '@fortawesome/free-solid-svg-icons'; import dayjs from 'dayjs/esm'; -import { MetisService } from 'app/shared/metis/metis.service'; -import { UserRole } from 'app/shared/metis/metis.util'; -import { IconProp } from '@fortawesome/fontawesome-svg-core'; -import { faUser, faUserCheck, faUserGraduate } from '@fortawesome/free-solid-svg-icons'; +import { CachingStrategy } from 'app/shared/image/secured-image.component'; +import { Posting } from 'app/entities/metis/posting.model'; import { User } from 'app/core/user/user.model'; +import { IconProp } from '@fortawesome/fontawesome-svg-core'; +import { MetisService } from 'app/shared/metis/metis.service'; import { AccountService } from 'app/core/auth/account.service'; import { tap } from 'rxjs'; +import { faUser, faUserCheck, faUserGraduate } from '@fortawesome/free-solid-svg-icons'; +import { UserRole } from 'app/shared/metis/metis.util'; +import { AnswerPost } from 'app/entities/metis/answer-post.model'; +import { Post } from 'app/entities/metis/post.model'; -@Directive() -export abstract class PostingHeaderDirective implements OnInit { - @Input() posting: T; - @Input() isCommunicationPage: boolean; - - @Input() hasChannelModerationRights = false; - @Output() isModalOpen = new EventEmitter(); +@Component({ + selector: 'jhi-posting-header', + templateUrl: './posting-header.component.html', + styleUrls: ['../../metis.component.scss'], +}) +export class PostingHeaderComponent implements OnInit, OnDestroy, OnChanges { + readOnlyMode = input(false); + lastReadDate = input(); + previewMode = input(false); + @ViewChild(PostCreateEditModalComponent) postCreateEditModal?: PostCreateEditModalComponent; + isAtLeastInstructorInCourse: boolean; + posting = input(); + isCommunicationPage = input(); + hasChannelModerationRights = input(false); + isModalOpen = output(); isDeleted = input(false); - isAtLeastTutorInCourse: boolean; isAuthorOfPosting: boolean; postingIsOfToday: boolean; todayFlag?: string; @@ -29,22 +41,54 @@ export abstract class PostingHeaderDirective implements OnIni userAuthorityTooltip: string; currentUser?: User; + // Icons + readonly faPencilAlt = faPencilAlt; + readonly faCheckSquare = faCheckSquare; + protected metisService: MetisService = inject(MetisService); protected accountService: AccountService = inject(AccountService); /** - * on initialization: determines if user is at least tutor in the course and if user is author of posting by invoking the metis service, + * on initialization: determines if user is author of posting by invoking the metis service, * determines if posting is of today and sets the today flag to be shown in the header of the posting * determines icon and tooltip for authority type of the author */ ngOnInit(): void { this.accountService .getAuthenticationState() - .pipe(tap((user: User) => (this.currentUser = user))) + .pipe( + tap((user: User) => { + this.currentUser = user; + this.setUserProperties(); + }), + ) .subscribe(); - this.postingIsOfToday = dayjs().isSame(this.posting.creationDate, 'day'); + this.postingIsOfToday = dayjs().isSame(this.posting()?.creationDate, 'day'); this.todayFlag = this.getTodayFlag(); + } + + private isPost(posting: Posting | AnswerPost | undefined): posting is Post { + return posting !== undefined && 'resolved' in posting; + } + + get isPostResolved(): boolean { + const p = this.posting(); + return this.isPost(p) && p.resolved === true; + } + + /** + * on changes: re-evaluates authority roles + */ + ngOnChanges() { this.setUserProperties(); + this.setUserAuthorityIconAndTooltip(); + } + + /** + * on leaving the page, the modal should be closed + */ + ngOnDestroy(): void { + this.postCreateEditModal?.modalRef?.close(); } /** @@ -61,14 +105,12 @@ export abstract class PostingHeaderDirective implements OnIni /** * Sets various user properties related to the posting and course. * Checks if the current user is the author of the posting and sets the `isAuthorOfPosting` flag accordingly. - * Checks if the current user has at least a tutor role in the course and sets the `isAtLeastTutorInCourse` flag accordingly. * Calls `setUserAuthorityIconAndTooltip()` to set the user's authority icon and tooltip based on their role. * * @returns {void} */ setUserProperties(): void { - this.isAuthorOfPosting = this.metisService.metisUserIsAuthorOfPosting(this.posting); - this.isAtLeastTutorInCourse = this.metisService.metisUserIsAtLeastTutorInCourse(); + this.isAuthorOfPosting = this.metisService.metisUserIsAuthorOfPosting(this.posting()!); this.setUserAuthorityIconAndTooltip(); } @@ -79,16 +121,16 @@ export abstract class PostingHeaderDirective implements OnIni const toolTipTranslationPath = 'artemisApp.metis.userAuthorityTooltips.'; const roleBadgeTranslationPath = 'artemisApp.metis.userRoles.'; this.userAuthorityIcon = faUser; - if (this.posting.authorRole === UserRole.USER) { + if (this.posting()?.authorRole === UserRole.USER) { this.userAuthority = 'student'; this.userRoleBadge = roleBadgeTranslationPath + this.userAuthority; this.userAuthorityTooltip = toolTipTranslationPath + this.userAuthority; - } else if (this.posting.authorRole === UserRole.INSTRUCTOR) { + } else if (this.posting()?.authorRole === UserRole.INSTRUCTOR) { this.userAuthorityIcon = faUserGraduate; this.userAuthority = 'instructor'; this.userRoleBadge = roleBadgeTranslationPath + this.userAuthority; this.userAuthorityTooltip = toolTipTranslationPath + this.userAuthority; - } else if (this.posting.authorRole === UserRole.TUTOR) { + } else if (this.posting()?.authorRole === UserRole.TUTOR) { this.userAuthorityIcon = faUserCheck; this.userAuthority = 'tutor'; this.userRoleBadge = roleBadgeTranslationPath + this.userAuthority; @@ -99,4 +141,6 @@ export abstract class PostingHeaderDirective implements OnIni this.userAuthorityTooltip = 'artemisApp.metis.userAuthorityTooltips.deleted'; } } + + protected readonly CachingStrategy = CachingStrategy; } diff --git a/src/test/javascript/spec/component/shared/metis/post/post.component.spec.ts b/src/test/javascript/spec/component/shared/metis/post/post.component.spec.ts index 6c0859326aaa..116a2d1cb9af 100644 --- a/src/test/javascript/spec/component/shared/metis/post/post.component.spec.ts +++ b/src/test/javascript/spec/component/shared/metis/post/post.component.spec.ts @@ -5,7 +5,7 @@ import { HtmlForMarkdownPipe } from 'app/shared/pipes/html-for-markdown.pipe'; import { PostComponent } from 'app/shared/metis/post/post.component'; import { getElement } from '../../../../helpers/utils/general.utils'; import { PostFooterComponent } from 'app/shared/metis/posting-footer/post-footer/post-footer.component'; -import { PostHeaderComponent } from 'app/shared/metis/posting-header/post-header/post-header.component'; +import { PostingHeaderComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-header/post-header/posting-header.component'; import { PostingContentComponent } from 'app/shared/metis/posting-content/posting-content.components'; import { MockMetisService } from '../../../../helpers/mocks/service/mock-metis-service.service'; import { MetisService } from 'app/shared/metis/metis.service'; @@ -69,7 +69,7 @@ describe('PostComponent', () => { PostComponent, FaIconComponent, // we want to test the type of rendered icons, therefore we cannot mock the component MockPipe(HtmlForMarkdownPipe), - MockComponent(PostHeaderComponent), + MockComponent(PostingHeaderComponent), MockComponent(PostingContentComponent), MockComponent(PostFooterComponent), MockComponent(AnswerPostCreateEditModalComponent), diff --git a/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts b/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts index 8071b5a84a95..8f4da18950eb 100644 --- a/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts +++ b/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts @@ -17,6 +17,8 @@ import { MockMetisService } from '../../../../../helpers/mocks/service/mock-meti import { metisPostExerciseUser1, post, unsortedAnswerArray } from '../../../../../helpers/sample/metis-sample-data'; import { AnswerPost } from 'app/entities/metis/answer-post.model'; import { User } from 'app/core/user/user.model'; +import { Injector, input, runInInjectionContext } from '@angular/core'; +import { Posting } from 'app/entities/metis/posting.model'; interface PostGroup { author: User | undefined; @@ -28,6 +30,7 @@ describe('PostFooterComponent', () => { let fixture: ComponentFixture; let metisService: MetisService; let metisServiceUserAuthorityStub: jest.SpyInstance; + let injector: Injector; beforeEach(() => { return TestBed.configureTestingModule({ @@ -53,6 +56,7 @@ describe('PostFooterComponent', () => { component = fixture.componentInstance; metisService = TestBed.inject(MetisService); metisServiceUserAuthorityStub = jest.spyOn(metisService, 'metisUserIsAtLeastTutorInCourse'); + injector = fixture.debugElement.injector; }); }); @@ -61,27 +65,33 @@ describe('PostFooterComponent', () => { }); it('should be initialized correctly for users that are at least tutors in course', () => { - component.posting = post; - component.posting.answers = unsortedAnswerArray; - metisServiceUserAuthorityStub.mockReturnValue(true); - component.ngOnInit(); - expect(component.isAtLeastTutorInCourse).toBeTrue(); - expect(component.createdAnswerPost.resolvesPost).toBeTrue(); + runInInjectionContext(injector, () => { + post.answers = unsortedAnswerArray; + component.posting = input(post); + metisServiceUserAuthorityStub.mockReturnValue(true); + component.ngOnInit(); + expect(component.isAtLeastTutorInCourse).toBeTrue(); + expect(component.createdAnswerPost.resolvesPost).toBeTrue(); + }); }); it('should group answer posts correctly', () => { - component.sortedAnswerPosts = unsortedAnswerArray; - component.groupAnswerPosts(); - expect(component.groupedAnswerPosts.length).toBeGreaterThan(0); // Ensure groups are created - expect(component.groupedAnswerPosts[0].posts.length).toBeGreaterThan(0); // Ensure posts exist in groups + runInInjectionContext(injector, () => { + component.sortedAnswerPosts = input(unsortedAnswerArray); + component.groupAnswerPosts(); + expect(component.groupedAnswerPosts.length).toBeGreaterThan(0); // Ensure groups are created + expect(component.groupedAnswerPosts[0].posts.length).toBeGreaterThan(0); // Ensure posts exist in groups + }); }); it('should group answer posts and detect changes on changes to sortedAnswerPosts input', () => { - const changeDetectorSpy = jest.spyOn(component['changeDetector'], 'detectChanges'); - component.sortedAnswerPosts = unsortedAnswerArray; - component.ngOnChanges({ sortedAnswerPosts: { currentValue: unsortedAnswerArray, previousValue: [], firstChange: true, isFirstChange: () => true } }); - expect(component.groupedAnswerPosts.length).toBeGreaterThan(0); - expect(changeDetectorSpy).toHaveBeenCalled(); + runInInjectionContext(injector, () => { + component.sortedAnswerPosts = input(unsortedAnswerArray); + const changeDetectorSpy = jest.spyOn(component['changeDetector'], 'detectChanges'); + component.ngOnChanges({ sortedAnswerPosts: { currentValue: unsortedAnswerArray, previousValue: [], firstChange: true, isFirstChange: () => true } }); + expect(component.groupedAnswerPosts.length).toBeGreaterThan(0); + expect(changeDetectorSpy).toHaveBeenCalled(); + }); }); it('should clear answerPostCreateEditModal container on destroy', () => { @@ -135,29 +145,35 @@ describe('PostFooterComponent', () => { }); it('should be initialized correctly for users that are not at least tutors in course', () => { - component.posting = post; - component.posting.answers = unsortedAnswerArray; - metisServiceUserAuthorityStub.mockReturnValue(false); - component.ngOnInit(); - expect(component.isAtLeastTutorInCourse).toBeFalse(); - expect(component.createdAnswerPost.resolvesPost).toBeFalse(); + runInInjectionContext(injector, () => { + component.posting = input(post); + component.posting.answers = unsortedAnswerArray; + metisServiceUserAuthorityStub.mockReturnValue(false); + component.ngOnInit(); + expect(component.isAtLeastTutorInCourse).toBeFalse(); + expect(component.createdAnswerPost.resolvesPost).toBeFalse(); + }); }); it('should open create answer post modal', () => { - component.posting = metisPostExerciseUser1; - component.ngOnInit(); - fixture.detectChanges(); - const createAnswerPostModalOpen = jest.spyOn(component.createAnswerPostModalComponent, 'open'); - component.openCreateAnswerPostModal(); - expect(createAnswerPostModalOpen).toHaveBeenCalledOnce(); + runInInjectionContext(injector, () => { + component.posting = input(metisPostExerciseUser1); + component.ngOnInit(); + fixture.detectChanges(); + const createAnswerPostModalOpen = jest.spyOn(component.createAnswerPostModalComponent, 'open'); + component.openCreateAnswerPostModal(); + expect(createAnswerPostModalOpen).toHaveBeenCalledOnce(); + }); }); it('should close create answer post modal', () => { - component.posting = metisPostExerciseUser1; - component.ngOnInit(); - fixture.detectChanges(); - const createAnswerPostModalClose = jest.spyOn(component.createAnswerPostModalComponent, 'close'); - component.closeCreateAnswerPostModal(); - expect(createAnswerPostModalClose).toHaveBeenCalledOnce(); + runInInjectionContext(injector, () => { + component.posting = input(metisPostExerciseUser1); + component.ngOnInit(); + fixture.detectChanges(); + const createAnswerPostModalClose = jest.spyOn(component.createAnswerPostModalComponent, 'close'); + component.closeCreateAnswerPostModal(); + expect(createAnswerPostModalClose).toHaveBeenCalledOnce(); + }); }); }); diff --git a/src/test/javascript/spec/component/shared/metis/postings-header/answer-post-header/answer-post-header.component.spec.ts b/src/test/javascript/spec/component/shared/metis/postings-header/answer-post-header/answer-post-header.component.spec.ts deleted file mode 100644 index 20bcc78bd7e8..000000000000 --- a/src/test/javascript/spec/component/shared/metis/postings-header/answer-post-header/answer-post-header.component.spec.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MetisService } from 'app/shared/metis/metis.service'; -import { MetisModule } from 'app/shared/metis/metis.module'; -import { MockMetisService } from '../../../../../helpers/mocks/service/mock-metis-service.service'; -import { DebugElement, ViewContainerRef } from '@angular/core'; -import dayjs from 'dayjs/esm'; -import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; -import { ArtemisDatePipe } from 'app/shared/pipes/artemis-date.pipe'; -import { getElement } from '../../../../../helpers/utils/general.utils'; -import { AnswerPostHeaderComponent } from 'app/shared/metis/posting-header/answer-post-header/answer-post-header.component'; -import { MockNgbModalService } from '../../../../../helpers/mocks/service/mock-ngb-modal.service'; -import { MockComponent, MockDirective, MockModule, MockPipe } from 'ng-mocks'; -import { MockViewContainerRef } from '../../../../../helpers/mocks/service/mock-view-container-ref.service'; -import { NgbModal, NgbTooltip } from '@ng-bootstrap/ng-bootstrap'; -import { AnswerPostCreateEditModalComponent } from 'app/shared/metis/posting-create-edit-modal/answer-post-create-edit-modal/answer-post-create-edit-modal.component'; -import { FormBuilder, FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { FaIconComponent } from '@fortawesome/angular-fontawesome'; -import { ConfirmIconComponent } from 'app/shared/confirm-icon/confirm-icon.component'; -import { PostingMarkdownEditorComponent } from 'app/shared/metis/posting-markdown-editor/posting-markdown-editor.component'; -import { PostingButtonComponent } from 'app/shared/metis/posting-button/posting-button.component'; -import { metisAnswerPostUser2, metisResolvingAnswerPostUser1, metisUser1 } from '../../../../../helpers/sample/metis-sample-data'; -import { AccountService } from 'app/core/auth/account.service'; -import { MockAccountService } from '../../../../../helpers/mocks/service/mock-account.service'; -import { ProfilePictureComponent } from 'app/shared/profile-picture/profile-picture.component'; - -describe('AnswerPostHeaderComponent', () => { - let component: AnswerPostHeaderComponent; - let fixture: ComponentFixture; - let debugElement: DebugElement; - let metisService: MetisService; - let metisServiceUserIsAtLeastTutorMock: jest.SpyInstance; - let metisServiceUserPostingAuthorMock: jest.SpyInstance; - - const yesterday: dayjs.Dayjs = dayjs().subtract(1, 'day'); - - beforeEach(() => { - return TestBed.configureTestingModule({ - imports: [MockModule(FormsModule), MockModule(ReactiveFormsModule), MockDirective(NgbTooltip), MockModule(MetisModule)], - providers: [ - FormBuilder, - { provide: MetisService, useClass: MockMetisService }, - { - provide: NgbModal, - useClass: MockNgbModalService, - }, - { provide: ViewContainerRef, useClass: MockViewContainerRef }, - { provide: AccountService, useClass: MockAccountService }, - ], - declarations: [ - AnswerPostHeaderComponent, - AnswerPostCreateEditModalComponent, - MockPipe(ArtemisTranslatePipe), - MockPipe(ArtemisDatePipe), - MockComponent(PostingMarkdownEditorComponent), - MockComponent(PostingButtonComponent), - MockComponent(FaIconComponent), - MockComponent(ConfirmIconComponent), - MockComponent(ProfilePictureComponent), - ], - }) - .compileComponents() - .then(() => { - fixture = TestBed.createComponent(AnswerPostHeaderComponent); - component = fixture.componentInstance; - metisService = TestBed.inject(MetisService); - metisServiceUserIsAtLeastTutorMock = jest.spyOn(metisService, 'metisUserIsAtLeastTutorInCourse'); - metisServiceUserPostingAuthorMock = jest.spyOn(metisService, 'metisUserIsAuthorOfPosting'); - debugElement = fixture.debugElement; - component.posting = metisResolvingAnswerPostUser1; - component.posting.creationDate = yesterday; - component.ngOnInit(); - component.userRoleBadge = 'artemisApp.metis.userRoles.student'; - component.todayFlag = 'artemisApp.metis.today'; - }); - }); - - afterEach(() => { - jest.restoreAllMocks(); - }); - - it('should set author information correctly', () => { - fixture.detectChanges(); - const headerAuthorAndDate = getElement(debugElement, '#header-author-date'); - expect(headerAuthorAndDate).not.toBeNull(); - expect(headerAuthorAndDate.innerHTML).toContain(metisUser1.name); - }); - - it('should set date information correctly for post of yesterday', () => { - component.posting.creationDate = yesterday; - component.ngOnInit(); - fixture.detectChanges(); - expect(getElement(debugElement, '#today-flag')).toBeNull(); - }); - - it('should initialize answer post not marked as resolved and not show the check to mark it as such', () => { - // user, that is not author of original post, should not see the check to mark an answer post as resolving - metisServiceUserIsAtLeastTutorMock.mockReturnValue(false); - metisServiceUserPostingAuthorMock.mockReturnValue(false); - // answer post that is not resolving original post - component.posting = metisAnswerPostUser2; - component.ngOnInit(); - fixture.detectChanges(); - expect(getElement(debugElement, '.resolved')).toBeNull(); - expect(getElement(debugElement, '.notResolved')).toBeNull(); - }); -}); diff --git a/src/test/javascript/spec/component/shared/metis/postings-header/post-header/post-header.component.spec.ts b/src/test/javascript/spec/component/shared/metis/postings-header/post-header/post-header.component.spec.ts deleted file mode 100644 index 1074da5a09fa..000000000000 --- a/src/test/javascript/spec/component/shared/metis/postings-header/post-header/post-header.component.spec.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MetisService } from 'app/shared/metis/metis.service'; -import { MetisModule } from 'app/shared/metis/metis.module'; -import { DebugElement } from '@angular/core'; -import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; -import { MockComponent, MockDirective, MockModule, MockPipe } from 'ng-mocks'; -import { getElement } from '../../../../../helpers/utils/general.utils'; -import { MockMetisService } from '../../../../../helpers/mocks/service/mock-metis-service.service'; -import { PostHeaderComponent } from 'app/shared/metis/posting-header/post-header/post-header.component'; -import { ArtemisDatePipe } from 'app/shared/pipes/artemis-date.pipe'; -import { PostCreateEditModalComponent } from 'app/shared/metis/posting-create-edit-modal/post-create-edit-modal/post-create-edit-modal.component'; -import { FormBuilder, FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { ConfirmIconComponent } from 'app/shared/confirm-icon/confirm-icon.component'; -import { FaIconComponent } from '@fortawesome/angular-fontawesome'; -import { PostingMarkdownEditorComponent } from 'app/shared/metis/posting-markdown-editor/posting-markdown-editor.component'; -import { PostingButtonComponent } from 'app/shared/metis/posting-button/posting-button.component'; -import { metisAnnouncement, metisPostExerciseUser1, metisPostLectureUser1 } from '../../../../../helpers/sample/metis-sample-data'; -import { UserRole } from 'app/shared/metis/metis.util'; -import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap'; -import { AccountService } from 'app/core/auth/account.service'; -import { MockAccountService } from '../../../../../helpers/mocks/service/mock-account.service'; -import { ProfilePictureComponent } from 'app/shared/profile-picture/profile-picture.component'; - -describe('PostHeaderComponent', () => { - let component: PostHeaderComponent; - let fixture: ComponentFixture; - let debugElement: DebugElement; - beforeEach(() => { - return TestBed.configureTestingModule({ - imports: [MockModule(FormsModule), MockModule(ReactiveFormsModule), MockDirective(NgbTooltip), MockModule(MetisModule)], - providers: [FormBuilder, { provide: MetisService, useClass: MockMetisService }, { provide: AccountService, useClass: MockAccountService }], - declarations: [ - PostHeaderComponent, - FaIconComponent, // we want to test the type of rendered icons, therefore we cannot mock the component - MockComponent(PostCreateEditModalComponent), - MockPipe(ArtemisTranslatePipe), - MockPipe(ArtemisDatePipe), - MockComponent(PostingMarkdownEditorComponent), - MockComponent(PostingButtonComponent), - MockComponent(ConfirmIconComponent), - MockComponent(ProfilePictureComponent), - ], - }) - .compileComponents() - .then(() => { - fixture = TestBed.createComponent(PostHeaderComponent); - component = fixture.componentInstance; - debugElement = fixture.debugElement; - component.posting = metisPostLectureUser1; - component.ngOnInit(); - }); - }); - - afterEach(() => { - jest.restoreAllMocks(); - }); - - it('should set date information correctly for post of today', () => { - fixture.detectChanges(); - expect(getElement(debugElement, '#today-flag')).toBeDefined(); - }); - - it('should display resolved icon on resolved post header', () => { - component.posting = metisPostExerciseUser1; - component.posting.resolved = true; - - component.ngOnInit(); - fixture.detectChanges(); - - expect(getElement(debugElement, '.resolved')).not.toBeNull(); - }); - - it.each` - input | expect - ${UserRole.INSTRUCTOR} | ${'post-authority-icon-instructor'} - ${UserRole.TUTOR} | ${'post-authority-icon-tutor'} - ${UserRole.USER} | ${'post-authority-icon-student'} - `('should display relevant icon and tooltip for author authority', (param: { input: UserRole; expect: string }) => { - component.posting = metisAnnouncement; - component.posting.authorRole = param.input; - component.ngOnInit(); - fixture.detectChanges(); - - // should display relevant icon for author authority - const badge = getElement(debugElement, '#role-badge'); - expect(badge).not.toBeNull(); - expect(badge.classList.contains(param.expect)).toBeTrue(); - }); -}); diff --git a/src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts b/src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts new file mode 100644 index 000000000000..fa9e3b66aa55 --- /dev/null +++ b/src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts @@ -0,0 +1,208 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MetisService } from '../../../../../../../main/webapp/app/shared/metis/metis.service'; +import { MetisModule } from '../../../../../../../main/webapp/app/shared/metis/metis.module'; +import { DebugElement, Injector, input, runInInjectionContext } from '@angular/core'; +import { ArtemisTranslatePipe } from '../../../../../../../main/webapp/app/shared/pipes/artemis-translate.pipe'; +import { MockComponent, MockDirective, MockModule, MockPipe } from 'ng-mocks'; +import { getElement } from '../../../../helpers/utils/general.utils'; +import { MockMetisService } from '../../../../helpers/mocks/service/mock-metis-service.service'; +import { PostingHeaderComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-header/post-header/posting-header.component'; +import { ArtemisDatePipe } from '../../../../../../../main/webapp/app/shared/pipes/artemis-date.pipe'; +import { PostCreateEditModalComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-create-edit-modal/post-create-edit-modal/post-create-edit-modal.component'; +import { FormBuilder, FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { ConfirmIconComponent } from '../../../../../../../main/webapp/app/shared/confirm-icon/confirm-icon.component'; +import { FaIconComponent } from '@fortawesome/angular-fontawesome'; +import { PostingMarkdownEditorComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-markdown-editor/posting-markdown-editor.component'; +import { PostingButtonComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-button/posting-button.component'; +import { metisPostExerciseUser1, metisPostLectureUser1, metisResolvingAnswerPostUser1, metisUser1 } from '../../../../helpers/sample/metis-sample-data'; +import { UserRole } from '../../../../../../../main/webapp/app/shared/metis/metis.util'; +import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap'; +import { AccountService } from '../../../../../../../main/webapp/app/core/auth/account.service'; +import { MockAccountService } from '../../../../helpers/mocks/service/mock-account.service'; +import { ProfilePictureComponent } from 'app/shared/profile-picture/profile-picture.component'; +import { Posting } from 'app/entities/metis/posting.model'; +import { Post } from 'app/entities/metis/post.model'; +import { faUser, faUserCheck, faUserGraduate } from '@fortawesome/free-solid-svg-icons'; +import { IconProp } from '@fortawesome/fontawesome-svg-core'; +import dayjs from 'dayjs/esm'; + +describe('PostingHeaderComponent', () => { + let component: PostingHeaderComponent; + let fixture: ComponentFixture; + let debugElement: DebugElement; + let injector: Injector; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [MockModule(FormsModule), MockModule(ReactiveFormsModule), MockDirective(NgbTooltip), MockModule(MetisModule)], + providers: [FormBuilder, { provide: MetisService, useClass: MockMetisService }, { provide: AccountService, useClass: MockAccountService }], + declarations: [ + PostingHeaderComponent, + FaIconComponent, + MockComponent(PostCreateEditModalComponent), + MockPipe(ArtemisTranslatePipe), + MockPipe(ArtemisDatePipe), + MockComponent(PostingMarkdownEditorComponent), + MockComponent(PostingButtonComponent), + MockComponent(ConfirmIconComponent), + MockComponent(ProfilePictureComponent), + ], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(PostingHeaderComponent); + component = fixture.componentInstance; + debugElement = fixture.debugElement; + injector = fixture.debugElement.injector; + }); + + afterEach(() => { + jest.restoreAllMocks(); + }); + + it('should set date information correctly for post of today', () => { + runInInjectionContext(injector, () => { + component.posting = input(metisPostLectureUser1); + component.ngOnInit(); + fixture.detectChanges(); + + expect(getElement(debugElement, '#today-flag')).toBeDefined(); + }); + }); + + it('should not set today flag for posts not created today', () => { + runInInjectionContext(injector, () => { + const pastDatePost = { + ...metisPostLectureUser1, + creationDate: dayjs().subtract(1, 'day').toDate(), + } as unknown as Post; + component.posting = input(pastDatePost); + component.ngOnInit(); + fixture.detectChanges(); + + expect(getElement(debugElement, '#today-flag')).toBeNull(); + }); + }); + + it('should display resolved icon on resolved post header', () => { + runInInjectionContext(injector, () => { + const resolvedPost = { ...metisPostExerciseUser1, resolved: true } as Post; + component.posting = input(resolvedPost); + component.ngOnInit(); + fixture.detectChanges(); + + expect(getElement(debugElement, '.resolved')).not.toBeNull(); + }); + }); + + it('should not display resolved icon on unresolved post header', () => { + runInInjectionContext(injector, () => { + const unresolvedPost = { ...metisPostExerciseUser1, resolved: false } as Post; + component.posting = input(unresolvedPost); + component.ngOnInit(); + fixture.detectChanges(); + + expect(getElement(debugElement, '.resolved')).toBeNull(); + }); + }); + + it.each` + input | expectClass + ${UserRole.INSTRUCTOR} | ${'post-authority-icon-instructor'} + ${UserRole.TUTOR} | ${'post-authority-icon-tutor'} + ${UserRole.USER} | ${'post-authority-icon-student'} + `('should display relevant icon and tooltip for author authority $input', (param: { input: UserRole; expectClass: string }) => { + runInInjectionContext(injector, () => { + const rolePost = { ...metisPostLectureUser1, authorRole: param.input } as Post; + component.posting = input(rolePost); + component.ngOnInit(); + fixture.detectChanges(); + + const badge = getElement(debugElement, '#role-badge'); + expect(badge).not.toBeNull(); + expect(badge.classList.contains(param.expectClass)).toBeTrue(); + }); + }); + + it.each` + input | expectedIcon + ${UserRole.USER} | ${faUser} + ${UserRole.INSTRUCTOR} | ${faUserGraduate} + ${UserRole.TUTOR} | ${faUserCheck} + `('should set userAuthorityIcon correctly for role $input', (param: { input: UserRole; expectedIcon: IconProp }) => { + runInInjectionContext(injector, () => { + const rolePost = { ...metisPostLectureUser1, authorRole: param.input } as Post; + component.posting = input(rolePost); + component.ngOnInit(); + fixture.detectChanges(); + + expect(component.userAuthorityIcon).toEqual(param.expectedIcon); + }); + }); + + it.each` + input | expectedTooltip + ${UserRole.USER} | ${'artemisApp.metis.userAuthorityTooltips.student'} + ${UserRole.INSTRUCTOR} | ${'artemisApp.metis.userAuthorityTooltips.instructor'} + ${UserRole.TUTOR} | ${'artemisApp.metis.userAuthorityTooltips.tutor'} + `('should set userAuthorityTooltip correctly for role $input', (param: { input: UserRole; expectedTooltip: string }) => { + runInInjectionContext(injector, () => { + const rolePost = { ...metisPostLectureUser1, authorRole: param.input } as Post; + component.posting = input(rolePost); + component.ngOnInit(); + fixture.detectChanges(); + + expect(component.userAuthorityTooltip).toEqual(param.expectedTooltip); + }); + }); + + it('should set isAuthorOfPosting correctly when user is the author', () => { + runInInjectionContext(injector, () => { + const authorPost = { ...metisPostLectureUser1, author: component.currentUser } as Post; + component.posting = input(authorPost); + component.ngOnInit(); + fixture.detectChanges(); + + expect(component.isAuthorOfPosting).toBeTrue(); + }); + }); + + it('should handle undefined posting gracefully', () => { + runInInjectionContext(injector, () => { + component.posting = input(); + component.ngOnInit(); + fixture.detectChanges(); + + expect(component.isPostResolved).toBeFalse(); + expect(getElement(debugElement, '.resolved')).toBeNull(); + }); + }); + + it('should set date information correctly for post of yesterday', () => { + runInInjectionContext(injector, () => { + const yesterday = dayjs().subtract(1, 'day').toDate(); + + const yesterdayPost: Post = { + ...metisPostLectureUser1, + creationDate: yesterday, + } as unknown as Post; + + component.posting = input(yesterdayPost); + component.ngOnInit(); + fixture.detectChanges(); + + expect(getElement(debugElement, '#today-flag')).toBeNull(); + }); + }); + + it('should set author information correctly', () => { + runInInjectionContext(injector, () => { + component.posting = input(metisResolvingAnswerPostUser1); + const headerAuthorAndDate = getElement(debugElement, '#header-author-date'); + fixture.detectChanges(); + expect(headerAuthorAndDate).not.toBeNull(); + expect(headerAuthorAndDate.innerHTML).toContain(metisUser1.name); + }); + }); +}); From bdceaff7d8026209f9bfe4501d3dbf373fd96691 Mon Sep 17 00:00:00 2001 From: Asli Aykan Date: Mon, 2 Dec 2024 23:00:55 +0100 Subject: [PATCH 02/13] fix tests --- .../metis/answer-post/answer-post.component.spec.ts | 12 ++++++------ .../post-footer/post-footer.component.spec.ts | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/javascript/spec/component/shared/metis/answer-post/answer-post.component.spec.ts b/src/test/javascript/spec/component/shared/metis/answer-post/answer-post.component.spec.ts index 3a84c4f12e87..3d9c17a422d1 100644 --- a/src/test/javascript/spec/component/shared/metis/answer-post/answer-post.component.spec.ts +++ b/src/test/javascript/spec/component/shared/metis/answer-post/answer-post.component.spec.ts @@ -4,7 +4,6 @@ import { DebugElement, input, runInInjectionContext } from '@angular/core'; import { MockComponent, MockModule, MockPipe, ngMocks } from 'ng-mocks'; import { HtmlForMarkdownPipe } from 'app/shared/pipes/html-for-markdown.pipe'; import { By } from '@angular/platform-browser'; -import { AnswerPostHeaderComponent } from 'app/shared/metis/posting-header/answer-post-header/answer-post-header.component'; import { AnswerPostReactionsBarComponent } from 'app/shared/metis/posting-reactions-bar/answer-post-reactions-bar/answer-post-reactions-bar.component'; import { PostingContentComponent } from 'app/shared/metis/posting-content/posting-content.components'; import { metisResolvingAnswerPostUser1 } from '../../../../helpers/sample/metis-sample-data'; @@ -17,6 +16,7 @@ import { MetisService } from 'app/shared/metis/metis.service'; import { MockMetisService } from '../../../../helpers/mocks/service/mock-metis-service.service'; import { Posting, PostingType } from 'app/entities/metis/posting.model'; import { AnswerPost } from 'app/entities/metis/answer-post.model'; +import { PostingHeaderComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-header/post-header/posting-header.component'; describe('AnswerPostComponent', () => { let component: AnswerPostComponent; @@ -34,8 +34,8 @@ describe('AnswerPostComponent', () => { declarations: [ AnswerPostComponent, MockPipe(HtmlForMarkdownPipe), - MockComponent(AnswerPostHeaderComponent), MockComponent(PostingContentComponent), + MockComponent(PostingHeaderComponent), MockComponent(AnswerPostCreateEditModalComponent), MockComponent(AnswerPostReactionsBarComponent), ], @@ -56,25 +56,25 @@ describe('AnswerPostComponent', () => { jest.restoreAllMocks(); }); - it('should contain an answer post header when isConsecutive is false', () => { + it('should contain the posting header when isConsecutive is false', () => { runInInjectionContext(fixture.debugElement.injector, () => { component.isConsecutive = input(false); component.posting = metisResolvingAnswerPostUser1; }); fixture.detectChanges(); - const header = debugElement.query(By.css('jhi-answer-post-header')); + const header = debugElement.query(By.css('jhi-posting-header')); expect(header).not.toBeNull(); }); - it('should not contain an answer post header when isConsecutive is true', () => { + it('should not contain the posting header when isConsecutive is true', () => { runInInjectionContext(fixture.debugElement.injector, () => { component.isConsecutive = input(true); component.posting = metisResolvingAnswerPostUser1; }); fixture.detectChanges(); - const header = debugElement.query(By.css('jhi-answer-post-header')); + const header = debugElement.query(By.css('jhi-posting-header')); expect(header).toBeNull(); }); diff --git a/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts b/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts index 8f4da18950eb..b89adb8ba320 100644 --- a/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts +++ b/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts @@ -146,8 +146,8 @@ describe('PostFooterComponent', () => { it('should be initialized correctly for users that are not at least tutors in course', () => { runInInjectionContext(injector, () => { + post.answers = unsortedAnswerArray; component.posting = input(post); - component.posting.answers = unsortedAnswerArray; metisServiceUserAuthorityStub.mockReturnValue(false); component.ngOnInit(); expect(component.isAtLeastTutorInCourse).toBeFalse(); From 9a7239fcf5d4e2de96a9938ea9cc2b9638cf7e50 Mon Sep 17 00:00:00 2001 From: Asli Aykan Date: Mon, 2 Dec 2024 23:03:49 +0100 Subject: [PATCH 03/13] refactor --- .../metis/postings-header/posting-header.component.spec.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts b/src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts index fa9e3b66aa55..3e9edd1cd7e6 100644 --- a/src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts +++ b/src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts @@ -48,9 +48,7 @@ describe('PostingHeaderComponent', () => { MockComponent(ProfilePictureComponent), ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(PostingHeaderComponent); component = fixture.componentInstance; debugElement = fixture.debugElement; From c203cb2dc75549e79b32bd62f6452eff49b46cd6 Mon Sep 17 00:00:00 2001 From: Asli Aykan Date: Tue, 3 Dec 2024 00:04:19 +0100 Subject: [PATCH 04/13] used viewChild instead of @ViewChild --- .../post-footer/post-footer.component.ts | 26 ++++++++++++++----- .../post-header/posting-header.component.ts | 6 ++--- .../post-footer/post-footer.component.spec.ts | 26 ++++++++++++------- 3 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts b/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts index fb7cfb890392..f2313a9b5103 100644 --- a/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts +++ b/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts @@ -1,4 +1,18 @@ -import { AfterContentChecked, ChangeDetectorRef, Component, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewChild, ViewContainerRef, inject, input, output } from '@angular/core'; +import { + AfterContentChecked, + ChangeDetectorRef, + Component, + OnChanges, + OnDestroy, + OnInit, + SimpleChanges, + ViewChild, + ViewContainerRef, + inject, + input, + output, + viewChild, +} from '@angular/core'; import { Post } from 'app/entities/metis/post.model'; import { MetisService } from 'app/shared/metis/metis.service'; import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; @@ -35,9 +49,9 @@ export class PostFooterComponent implements OnInit, OnDestroy, AfterContentCheck userReferenceClicked = output(); channelReferenceClicked = output(); - @ViewChild(AnswerPostCreateEditModalComponent) answerPostCreateEditModal?: AnswerPostCreateEditModalComponent; @ViewChild('createEditAnswerPostContainer', { read: ViewContainerRef }) containerRef!: ViewContainerRef; - @ViewChild('createAnswerPostModal') createAnswerPostModalComponent!: AnswerPostCreateEditModalComponent; + answerPostCreateEditModal = viewChild(AnswerPostCreateEditModalComponent); + createAnswerPostModalComponent = viewChild('createAnswerPostModal'); createdAnswerPost: AnswerPost; isAtLeastTutorInCourse = false; @@ -62,7 +76,7 @@ export class PostFooterComponent implements OnInit, OnDestroy, AfterContentCheck } ngOnDestroy(): void { - this.answerPostCreateEditModal?.createEditAnswerPostContainerRef?.clear(); + this.answerPostCreateEditModal()?.createEditAnswerPostContainerRef?.clear(); } /** @@ -156,14 +170,14 @@ export class PostFooterComponent implements OnInit, OnDestroy, AfterContentCheck * Open create answer modal */ openCreateAnswerPostModal() { - this.createAnswerPostModalComponent.open(); + this.createAnswerPostModalComponent()?.open(); } /** * Close create answer modal */ closeCreateAnswerPostModal() { - this.createAnswerPostModalComponent.close(); + this.createAnswerPostModalComponent()?.close(); } protected postsTrackByFn(index: number, post: Post): number { diff --git a/src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.ts b/src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.ts index 437619640f7c..a36929a89f77 100644 --- a/src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.ts +++ b/src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.ts @@ -1,4 +1,4 @@ -import { Component, OnChanges, OnDestroy, OnInit, ViewChild, inject, input, output } from '@angular/core'; +import { Component, OnChanges, OnDestroy, OnInit, inject, input, output, viewChild } from '@angular/core'; import { PostCreateEditModalComponent } from 'app/shared/metis/posting-create-edit-modal/post-create-edit-modal/post-create-edit-modal.component'; import { faCheckSquare, faPencilAlt } from '@fortawesome/free-solid-svg-icons'; import dayjs from 'dayjs/esm'; @@ -23,7 +23,7 @@ export class PostingHeaderComponent implements OnInit, OnDestroy, OnChanges { readOnlyMode = input(false); lastReadDate = input(); previewMode = input(false); - @ViewChild(PostCreateEditModalComponent) postCreateEditModal?: PostCreateEditModalComponent; + postCreateEditModal = viewChild(PostCreateEditModalComponent); isAtLeastInstructorInCourse: boolean; posting = input(); isCommunicationPage = input(); @@ -88,7 +88,7 @@ export class PostingHeaderComponent implements OnInit, OnDestroy, OnChanges { * on leaving the page, the modal should be closed */ ngOnDestroy(): void { - this.postCreateEditModal?.modalRef?.close(); + this.postCreateEditModal()?.modalRef?.close(); } /** diff --git a/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts b/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts index b89adb8ba320..51013065e383 100644 --- a/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts +++ b/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts @@ -19,6 +19,7 @@ import { AnswerPost } from 'app/entities/metis/answer-post.model'; import { User } from 'app/core/user/user.model'; import { Injector, input, runInInjectionContext } from '@angular/core'; import { Posting } from 'app/entities/metis/posting.model'; +import { By } from '@angular/platform-browser'; interface PostGroup { author: User | undefined; @@ -95,14 +96,19 @@ describe('PostFooterComponent', () => { }); it('should clear answerPostCreateEditModal container on destroy', () => { - const mockContainerRef = { clear: jest.fn() } as any; - component.answerPostCreateEditModal = { - createEditAnswerPostContainerRef: mockContainerRef, - } as AnswerPostCreateEditModalComponent; - - const clearSpy = jest.spyOn(mockContainerRef, 'clear'); - component.ngOnDestroy(); - expect(clearSpy).toHaveBeenCalled(); + runInInjectionContext(fixture.debugElement.injector, () => { + const mockAnswerPostCreateEditModalDE = fixture.debugElement.query(By.directive(AnswerPostCreateEditModalComponent)); + const mockAnswerPostCreateEditModal = mockAnswerPostCreateEditModalDE.componentInstance as AnswerPostCreateEditModalComponent; + + const mockContainerRef = { clear: jest.fn() } as any; + mockAnswerPostCreateEditModal.createEditAnswerPostContainerRef = mockContainerRef; + + const clearSpy = jest.spyOn(mockContainerRef, 'clear'); + + component.ngOnDestroy(); + + expect(clearSpy).toHaveBeenCalled(); + }); }); it('should return the ID of the post in trackPostByFn', () => { @@ -160,7 +166,7 @@ describe('PostFooterComponent', () => { component.posting = input(metisPostExerciseUser1); component.ngOnInit(); fixture.detectChanges(); - const createAnswerPostModalOpen = jest.spyOn(component.createAnswerPostModalComponent, 'open'); + const createAnswerPostModalOpen = jest.spyOn(component.createAnswerPostModalComponent()!, 'open'); component.openCreateAnswerPostModal(); expect(createAnswerPostModalOpen).toHaveBeenCalledOnce(); }); @@ -171,7 +177,7 @@ describe('PostFooterComponent', () => { component.posting = input(metisPostExerciseUser1); component.ngOnInit(); fixture.detectChanges(); - const createAnswerPostModalClose = jest.spyOn(component.createAnswerPostModalComponent, 'close'); + const createAnswerPostModalClose = jest.spyOn(component.createAnswerPostModalComponent()!, 'close'); component.closeCreateAnswerPostModal(); expect(createAnswerPostModalClose).toHaveBeenCalledOnce(); }); From 050dc6edc1a91b4081d9e8097098c7eb0d19873f Mon Sep 17 00:00:00 2001 From: Asli Aykan Date: Tue, 3 Dec 2024 00:29:54 +0100 Subject: [PATCH 05/13] revert --- .../posting-header/post-header/posting-header.component.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.ts b/src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.ts index a36929a89f77..437619640f7c 100644 --- a/src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.ts +++ b/src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.ts @@ -1,4 +1,4 @@ -import { Component, OnChanges, OnDestroy, OnInit, inject, input, output, viewChild } from '@angular/core'; +import { Component, OnChanges, OnDestroy, OnInit, ViewChild, inject, input, output } from '@angular/core'; import { PostCreateEditModalComponent } from 'app/shared/metis/posting-create-edit-modal/post-create-edit-modal/post-create-edit-modal.component'; import { faCheckSquare, faPencilAlt } from '@fortawesome/free-solid-svg-icons'; import dayjs from 'dayjs/esm'; @@ -23,7 +23,7 @@ export class PostingHeaderComponent implements OnInit, OnDestroy, OnChanges { readOnlyMode = input(false); lastReadDate = input(); previewMode = input(false); - postCreateEditModal = viewChild(PostCreateEditModalComponent); + @ViewChild(PostCreateEditModalComponent) postCreateEditModal?: PostCreateEditModalComponent; isAtLeastInstructorInCourse: boolean; posting = input(); isCommunicationPage = input(); @@ -88,7 +88,7 @@ export class PostingHeaderComponent implements OnInit, OnDestroy, OnChanges { * on leaving the page, the modal should be closed */ ngOnDestroy(): void { - this.postCreateEditModal()?.modalRef?.close(); + this.postCreateEditModal?.modalRef?.close(); } /** From ecba0b54e4df1d3d98a3dce66bbacf4c52ebfc04 Mon Sep 17 00:00:00 2001 From: Asli Aykan Date: Tue, 3 Dec 2024 00:43:14 +0100 Subject: [PATCH 06/13] revert --- .../post-footer/post-footer.component.ts | 26 +++++-------------- .../post-footer/post-footer.component.spec.ts | 26 +++++++------------ 2 files changed, 16 insertions(+), 36 deletions(-) diff --git a/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts b/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts index f2313a9b5103..70828febcadb 100644 --- a/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts +++ b/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts @@ -1,18 +1,4 @@ -import { - AfterContentChecked, - ChangeDetectorRef, - Component, - OnChanges, - OnDestroy, - OnInit, - SimpleChanges, - ViewChild, - ViewContainerRef, - inject, - input, - output, - viewChild, -} from '@angular/core'; +import { AfterContentChecked, ChangeDetectorRef, Component, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewChild, ViewContainerRef, inject, input, output } from '@angular/core'; import { Post } from 'app/entities/metis/post.model'; import { MetisService } from 'app/shared/metis/metis.service'; import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; @@ -49,9 +35,9 @@ export class PostFooterComponent implements OnInit, OnDestroy, AfterContentCheck userReferenceClicked = output(); channelReferenceClicked = output(); + @ViewChild(AnswerPostCreateEditModalComponent) answerPostCreateEditModal?: AnswerPostCreateEditModalComponent; @ViewChild('createEditAnswerPostContainer', { read: ViewContainerRef }) containerRef!: ViewContainerRef; - answerPostCreateEditModal = viewChild(AnswerPostCreateEditModalComponent); - createAnswerPostModalComponent = viewChild('createAnswerPostModal'); + @ViewChild('createAnswerPostModal') createAnswerPostModalComponent!: AnswerPostCreateEditModalComponent; createdAnswerPost: AnswerPost; isAtLeastTutorInCourse = false; @@ -76,7 +62,7 @@ export class PostFooterComponent implements OnInit, OnDestroy, AfterContentCheck } ngOnDestroy(): void { - this.answerPostCreateEditModal()?.createEditAnswerPostContainerRef?.clear(); + this.answerPostCreateEditModal?.createEditAnswerPostContainerRef?.clear(); } /** @@ -170,14 +156,14 @@ export class PostFooterComponent implements OnInit, OnDestroy, AfterContentCheck * Open create answer modal */ openCreateAnswerPostModal() { - this.createAnswerPostModalComponent()?.open(); + this.createAnswerPostModalComponent?.open(); } /** * Close create answer modal */ closeCreateAnswerPostModal() { - this.createAnswerPostModalComponent()?.close(); + this.createAnswerPostModalComponent?.close(); } protected postsTrackByFn(index: number, post: Post): number { diff --git a/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts b/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts index 51013065e383..b89adb8ba320 100644 --- a/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts +++ b/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts @@ -19,7 +19,6 @@ import { AnswerPost } from 'app/entities/metis/answer-post.model'; import { User } from 'app/core/user/user.model'; import { Injector, input, runInInjectionContext } from '@angular/core'; import { Posting } from 'app/entities/metis/posting.model'; -import { By } from '@angular/platform-browser'; interface PostGroup { author: User | undefined; @@ -96,19 +95,14 @@ describe('PostFooterComponent', () => { }); it('should clear answerPostCreateEditModal container on destroy', () => { - runInInjectionContext(fixture.debugElement.injector, () => { - const mockAnswerPostCreateEditModalDE = fixture.debugElement.query(By.directive(AnswerPostCreateEditModalComponent)); - const mockAnswerPostCreateEditModal = mockAnswerPostCreateEditModalDE.componentInstance as AnswerPostCreateEditModalComponent; - - const mockContainerRef = { clear: jest.fn() } as any; - mockAnswerPostCreateEditModal.createEditAnswerPostContainerRef = mockContainerRef; - - const clearSpy = jest.spyOn(mockContainerRef, 'clear'); - - component.ngOnDestroy(); - - expect(clearSpy).toHaveBeenCalled(); - }); + const mockContainerRef = { clear: jest.fn() } as any; + component.answerPostCreateEditModal = { + createEditAnswerPostContainerRef: mockContainerRef, + } as AnswerPostCreateEditModalComponent; + + const clearSpy = jest.spyOn(mockContainerRef, 'clear'); + component.ngOnDestroy(); + expect(clearSpy).toHaveBeenCalled(); }); it('should return the ID of the post in trackPostByFn', () => { @@ -166,7 +160,7 @@ describe('PostFooterComponent', () => { component.posting = input(metisPostExerciseUser1); component.ngOnInit(); fixture.detectChanges(); - const createAnswerPostModalOpen = jest.spyOn(component.createAnswerPostModalComponent()!, 'open'); + const createAnswerPostModalOpen = jest.spyOn(component.createAnswerPostModalComponent, 'open'); component.openCreateAnswerPostModal(); expect(createAnswerPostModalOpen).toHaveBeenCalledOnce(); }); @@ -177,7 +171,7 @@ describe('PostFooterComponent', () => { component.posting = input(metisPostExerciseUser1); component.ngOnInit(); fixture.detectChanges(); - const createAnswerPostModalClose = jest.spyOn(component.createAnswerPostModalComponent()!, 'close'); + const createAnswerPostModalClose = jest.spyOn(component.createAnswerPostModalComponent, 'close'); component.closeCreateAnswerPostModal(); expect(createAnswerPostModalClose).toHaveBeenCalledOnce(); }); From ad99c3b39e1f204f79886bd96023acc63a381121 Mon Sep 17 00:00:00 2001 From: Asli Aykan Date: Fri, 6 Dec 2024 14:40:53 +0100 Subject: [PATCH 07/13] used computed --- .../post-header/posting-header.component.html | 2 +- .../post-header/posting-header.component.ts | 12 ++++++------ .../postings-header/posting-header.component.spec.ts | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.html b/src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.html index d8630a86ad89..016d99674901 100644 --- a/src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.html +++ b/src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.html @@ -34,7 +34,7 @@ {{ postingIsOfToday ? (posting()?.creationDate | artemisDate: 'time') : (posting()?.creationDate | artemisDate: 'short-date') }} - @if (isPostResolved) { + @if (isPostResolved()) { (() => { + const p = this.posting(); + return this.isPost(p) && p.resolved === true; + }); + /** * on initialization: determines if user is author of posting by invoking the metis service, * determines if posting is of today and sets the today flag to be shown in the header of the posting @@ -71,11 +76,6 @@ export class PostingHeaderComponent implements OnInit, OnDestroy, OnChanges { return posting !== undefined && 'resolved' in posting; } - get isPostResolved(): boolean { - const p = this.posting(); - return this.isPost(p) && p.resolved === true; - } - /** * on changes: re-evaluates authority roles */ diff --git a/src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts b/src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts index 3e9edd1cd7e6..b5a054b19cc2 100644 --- a/src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts +++ b/src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts @@ -172,7 +172,7 @@ describe('PostingHeaderComponent', () => { component.ngOnInit(); fixture.detectChanges(); - expect(component.isPostResolved).toBeFalse(); + expect(component.isPostResolved()).toBeFalse(); expect(getElement(debugElement, '.resolved')).toBeNull(); }); }); From e2356ec85398de63f023bafbac5669ef83a90a23 Mon Sep 17 00:00:00 2001 From: Asli Aykan Date: Sun, 8 Dec 2024 01:56:43 +0100 Subject: [PATCH 08/13] fix paranthesis --- .../posting-footer/post-footer/post-footer.component.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.html b/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.html index 42a08399cb45..56035668f4a2 100644 --- a/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.html +++ b/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.html @@ -2,9 +2,9 @@
{{ - sortedAnswerPosts.length === 1 + sortedAnswerPosts().length === 1 ? ('artemisApp.metis.singleAnswer' | artemisTranslate) - : ('artemisApp.metis.multipleAnswers' | artemisTranslate: { number: sortedAnswerPosts.length }) + : ('artemisApp.metis.multipleAnswers' | artemisTranslate: { number: sortedAnswerPosts().length }) }}
From d5e0e6d006295e81a5b06dab94881c69db83d01b Mon Sep 17 00:00:00 2001 From: Asli Aykan Date: Mon, 9 Dec 2024 14:53:15 +0100 Subject: [PATCH 09/13] resolved conflict --- .../post-footer/post-footer.component.spec.ts | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts b/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts index 1f7e454597e1..353df5e83415 100644 --- a/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts +++ b/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts @@ -80,8 +80,8 @@ describe('PostFooterComponent', () => { runInInjectionContext(injector, () => { component.sortedAnswerPosts = input(unsortedAnswerArray); component.groupAnswerPosts(); - expect(component.groupedAnswerPosts.length).toBeGreaterThan(0); // Ensure groups are created - expect(component.groupedAnswerPosts[0].posts.length).toBeGreaterThan(0); // Ensure posts exist in groups + expect(component.groupedAnswerPosts.length).toBeGreaterThan(0); + expect(component.groupedAnswerPosts[0].posts.length).toBeGreaterThan(0); }); }); @@ -189,27 +189,28 @@ describe('PostFooterComponent', () => { const post3: AnswerPost = { id: 3, author: authorA, creationDate: baseTime.add(10, 'minute').toDate() } as unknown as AnswerPost; const post4: AnswerPost = { id: 4, author: authorB, creationDate: baseTime.add(12, 'minute').toDate() } as unknown as AnswerPost; const post5: AnswerPost = { id: 5, author: authorB, creationDate: baseTime.add(14, 'minute').toDate() } as unknown as AnswerPost; + runInInjectionContext(injector, () => { + component.sortedAnswerPosts = input([post3, post1, post5, post2, post4]); - component.sortedAnswerPosts = [post3, post1, post5, post2, post4]; - - component.groupAnswerPosts(); - expect(component.groupedAnswerPosts).toHaveLength(3); - - const group1 = component.groupedAnswerPosts[0]; - expect(group1.author).toEqual(authorA); - expect(group1.posts).toHaveLength(2); - expect(group1.posts).toContainEqual(expect.objectContaining({ id: post1.id })); - expect(group1.posts).toContainEqual(expect.objectContaining({ id: post2.id })); - - const group2 = component.groupedAnswerPosts[1]; - expect(group2.author).toEqual(authorA); - expect(group2.posts).toHaveLength(1); - expect(group2.posts).toContainEqual(expect.objectContaining({ id: post3.id })); - - const group3 = component.groupedAnswerPosts[2]; - expect(group3.author).toEqual(authorB); - expect(group3.posts).toHaveLength(2); - expect(group3.posts).toContainEqual(expect.objectContaining({ id: post4.id })); - expect(group3.posts).toContainEqual(expect.objectContaining({ id: post5.id })); + component.groupAnswerPosts(); + expect(component.groupedAnswerPosts).toHaveLength(3); + + const group1 = component.groupedAnswerPosts[0]; + expect(group1.author).toEqual(authorA); + expect(group1.posts).toHaveLength(2); + expect(group1.posts).toContainEqual(expect.objectContaining({ id: post1.id })); + expect(group1.posts).toContainEqual(expect.objectContaining({ id: post2.id })); + + const group2 = component.groupedAnswerPosts[1]; + expect(group2.author).toEqual(authorA); + expect(group2.posts).toHaveLength(1); + expect(group2.posts).toContainEqual(expect.objectContaining({ id: post3.id })); + + const group3 = component.groupedAnswerPosts[2]; + expect(group3.author).toEqual(authorB); + expect(group3.posts).toHaveLength(2); + expect(group3.posts).toContainEqual(expect.objectContaining({ id: post4.id })); + expect(group3.posts).toContainEqual(expect.objectContaining({ id: post5.id })); + }); }); }); From 8632272ee1064eb00618d4bffc195fce2a676a94 Mon Sep 17 00:00:00 2001 From: Asli Aykan Date: Mon, 9 Dec 2024 15:59:37 +0100 Subject: [PATCH 10/13] renaming and refactoring --- .../webapp/app/shared/metis/metis.module.ts | 8 ++-- .../app/shared/metis/post/post.component.html | 2 +- .../app/shared/metis/post/post.component.ts | 4 +- .../post-footer/post-footer.component.scss | 13 ------ ...ent.html => posting-footer.component.html} | 0 ...mponent.ts => posting-footer.component.ts} | 7 ++- .../answer-post-header.component.html | 45 ------------------- .../posting-header.component.html | 26 +++++------ .../posting-header.component.ts | 14 +++++- .../answer-post/answer-post.component.spec.ts | 2 +- .../shared/metis/post/post.component.spec.ts | 8 ++-- ...ec.ts => posting-footer.component.spec.ts} | 44 +++++++++--------- .../posting-header.component.spec.ts | 2 +- 13 files changed, 62 insertions(+), 113 deletions(-) delete mode 100644 src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.scss rename src/main/webapp/app/shared/metis/posting-footer/{post-footer/post-footer.component.html => posting-footer.component.html} (100%) rename src/main/webapp/app/shared/metis/posting-footer/{post-footer/post-footer.component.ts => posting-footer.component.ts} (96%) delete mode 100644 src/main/webapp/app/shared/metis/posting-header/answer-post-header/answer-post-header.component.html rename src/main/webapp/app/shared/metis/posting-header/{post-header => }/posting-header.component.html (63%) rename src/main/webapp/app/shared/metis/posting-header/{post-header => }/posting-header.component.ts (94%) rename src/test/javascript/spec/component/shared/metis/postings-footer/{post-footer/post-footer.component.spec.ts => posting-footer.component.spec.ts} (81%) diff --git a/src/main/webapp/app/shared/metis/metis.module.ts b/src/main/webapp/app/shared/metis/metis.module.ts index a38882674ff1..1add6fdd7cb2 100644 --- a/src/main/webapp/app/shared/metis/metis.module.ts +++ b/src/main/webapp/app/shared/metis/metis.module.ts @@ -8,10 +8,10 @@ import { ArtemisMarkdownModule } from 'app/shared/markdown.module'; import { ArtemisMarkdownEditorModule } from 'app/shared/markdown-editor/markdown-editor.module'; import { PostingButtonComponent } from 'app/shared/metis/posting-button/posting-button.component'; import { PostingMarkdownEditorComponent } from 'app/shared/metis/posting-markdown-editor/posting-markdown-editor.component'; -import { PostingHeaderComponent } from 'app/shared/metis/posting-header/post-header/posting-header.component'; +import { PostingHeaderComponent } from 'app/shared/metis/posting-header/posting-header.component'; import { AnswerPostCreateEditModalComponent } from 'app/shared/metis/posting-create-edit-modal/answer-post-create-edit-modal/answer-post-create-edit-modal.component'; import { PostCreateEditModalComponent } from 'app/shared/metis/posting-create-edit-modal/post-create-edit-modal/post-create-edit-modal.component'; -import { PostFooterComponent } from 'app/shared/metis/posting-footer/post-footer/post-footer.component'; +import { PostingFooterComponent } from 'app/shared/metis/posting-footer/posting-footer.component'; import { PostTagSelectorComponent } from 'app/shared/metis/posting-create-edit-modal/post-create-edit-modal/post-tag-selector/post-tag-selector.component'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { ArtemisSharedComponentModule } from 'app/shared/components/shared-component.module'; @@ -70,7 +70,7 @@ import { ProfilePictureComponent } from 'app/shared/profile-picture/profile-pict PostingHeaderComponent, PostCreateEditModalComponent, PostTagSelectorComponent, - PostFooterComponent, + PostingFooterComponent, AnswerPostCreateEditModalComponent, PostingButtonComponent, PostingMarkdownEditorComponent, @@ -95,7 +95,7 @@ import { ProfilePictureComponent } from 'app/shared/profile-picture/profile-pict PostCreateEditModalComponent, PostTagSelectorComponent, AnswerPostCreateEditModalComponent, - PostFooterComponent, + PostingFooterComponent, PostingButtonComponent, PostingMarkdownEditorComponent, PostComponent, diff --git a/src/main/webapp/app/shared/metis/post/post.component.html b/src/main/webapp/app/shared/metis/post/post.component.html index 03815f9409d4..93ba98b6902b 100644 --- a/src/main/webapp/app/shared/metis/post/post.component.html +++ b/src/main/webapp/app/shared/metis/post/post.component.html @@ -146,7 +146,7 @@
}
- implements OnInit, OnC @ViewChild('createAnswerPostModal') createAnswerPostModalComponent: AnswerPostCreateEditModalComponent; @ViewChild('createEditModal') createEditModal!: PostCreateEditModalComponent; @ViewChild('createEditAnswerPostContainer', { read: ViewContainerRef }) containerRef: ViewContainerRef; - @ViewChild('postFooter') postFooterComponent: PostFooterComponent; + @ViewChild('postFooter') postFooterComponent: PostingFooterComponent; showReactionSelector = false; @ViewChild('emojiPickerTrigger') emojiPickerTrigger!: CdkOverlayOrigin; static activeDropdownPost: PostComponent | null = null; diff --git a/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.scss b/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.scss deleted file mode 100644 index 1b17c04ff2e2..000000000000 --- a/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.scss +++ /dev/null @@ -1,13 +0,0 @@ -@import 'src/main/webapp/app/shared/metis/metis.component'; - -.post-tag { - max-width: 150px; - overflow: hidden; - text-overflow: ellipsis; - background-color: var(--metis-light-blue); - border-radius: 3px; - white-space: nowrap; - font-size: smaller; - color: var(--metis-blue); - padding-bottom: 0.1rem; -} diff --git a/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.html b/src/main/webapp/app/shared/metis/posting-footer/posting-footer.component.html similarity index 100% rename from src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.html rename to src/main/webapp/app/shared/metis/posting-footer/posting-footer.component.html diff --git a/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts b/src/main/webapp/app/shared/metis/posting-footer/posting-footer.component.ts similarity index 96% rename from src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts rename to src/main/webapp/app/shared/metis/posting-footer/posting-footer.component.ts index c7506702d170..ae10785f2ff9 100644 --- a/src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts +++ b/src/main/webapp/app/shared/metis/posting-footer/posting-footer.component.ts @@ -14,11 +14,10 @@ interface PostGroup { } @Component({ - selector: 'jhi-post-footer', - templateUrl: './post-footer.component.html', - styleUrls: ['./post-footer.component.scss'], + selector: 'jhi-posting-footer', + templateUrl: './posting-footer.component.html', }) -export class PostFooterComponent implements OnInit, OnDestroy, AfterContentChecked, OnChanges { +export class PostingFooterComponent implements OnInit, OnDestroy, AfterContentChecked, OnChanges { lastReadDate = input(); readOnlyMode = input(false); previewMode = input(false); diff --git a/src/main/webapp/app/shared/metis/posting-header/answer-post-header/answer-post-header.component.html b/src/main/webapp/app/shared/metis/posting-header/answer-post-header/answer-post-header.component.html deleted file mode 100644 index f7d42ac92f61..000000000000 --- a/src/main/webapp/app/shared/metis/posting-header/answer-post-header/answer-post-header.component.html +++ /dev/null @@ -1,45 +0,0 @@ -
- -
diff --git a/src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.html b/src/main/webapp/app/shared/metis/posting-header/posting-header.component.html similarity index 63% rename from src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.html rename to src/main/webapp/app/shared/metis/posting-header/posting-header.component.html index deadcb377cdd..ace508c34243 100644 --- a/src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.html +++ b/src/main/webapp/app/shared/metis/posting-header/posting-header.component.html @@ -1,6 +1,6 @@ -
+
diff --git a/src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.ts b/src/main/webapp/app/shared/metis/posting-header/posting-header.component.ts similarity index 94% rename from src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.ts rename to src/main/webapp/app/shared/metis/posting-header/posting-header.component.ts index bac41af75bd5..919c75bb508c 100644 --- a/src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.ts +++ b/src/main/webapp/app/shared/metis/posting-header/posting-header.component.ts @@ -17,7 +17,7 @@ import { Post } from 'app/entities/metis/post.model'; @Component({ selector: 'jhi-posting-header', templateUrl: './posting-header.component.html', - styleUrls: ['../../metis.component.scss'], + styleUrls: ['../metis.component.scss'], }) export class PostingHeaderComponent implements OnInit, OnDestroy, OnChanges { readOnlyMode = input(false); @@ -84,6 +84,18 @@ export class PostingHeaderComponent implements OnInit, OnDestroy, OnChanges { this.setUserAuthorityIconAndTooltip(); } + get isAfter(): boolean | undefined { + return this.posting()?.creationDate?.isAfter(this.lastReadDate()); + } + + get authorOfPosting(): User | undefined { + return this.posting()?.author; + } + + get creationDate(): dayjs.Dayjs | undefined { + return this.posting()?.creationDate; + } + /** * on leaving the page, the modal should be closed */ diff --git a/src/test/javascript/spec/component/shared/metis/answer-post/answer-post.component.spec.ts b/src/test/javascript/spec/component/shared/metis/answer-post/answer-post.component.spec.ts index 5b10a35f941c..a35ce7b37516 100644 --- a/src/test/javascript/spec/component/shared/metis/answer-post/answer-post.component.spec.ts +++ b/src/test/javascript/spec/component/shared/metis/answer-post/answer-post.component.spec.ts @@ -16,7 +16,7 @@ import { MetisService } from 'app/shared/metis/metis.service'; import { MockMetisService } from '../../../../helpers/mocks/service/mock-metis-service.service'; import { Posting, PostingType } from 'app/entities/metis/posting.model'; import { AnswerPost } from 'app/entities/metis/answer-post.model'; -import { PostingHeaderComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-header/post-header/posting-header.component'; +import { PostingHeaderComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-header/posting-header.component'; import dayjs from 'dayjs/esm'; import { ArtemisDatePipe } from '../../../../../../../main/webapp/app/shared/pipes/artemis-date.pipe'; import { ArtemisTranslatePipe } from '../../../../../../../main/webapp/app/shared/pipes/artemis-translate.pipe'; diff --git a/src/test/javascript/spec/component/shared/metis/post/post.component.spec.ts b/src/test/javascript/spec/component/shared/metis/post/post.component.spec.ts index 5e29ab34b3c4..28dddeaf8aef 100644 --- a/src/test/javascript/spec/component/shared/metis/post/post.component.spec.ts +++ b/src/test/javascript/spec/component/shared/metis/post/post.component.spec.ts @@ -4,8 +4,8 @@ import { DebugElement } from '@angular/core'; import { HtmlForMarkdownPipe } from 'app/shared/pipes/html-for-markdown.pipe'; import { PostComponent } from 'app/shared/metis/post/post.component'; import { getElement } from '../../../../helpers/utils/general.utils'; -import { PostFooterComponent } from 'app/shared/metis/posting-footer/post-footer/post-footer.component'; -import { PostingHeaderComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-header/post-header/posting-header.component'; +import { PostingFooterComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-footer/posting-footer.component'; +import { PostingHeaderComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-header/posting-header.component'; import { PostingContentComponent } from 'app/shared/metis/posting-content/posting-content.components'; import { MockMetisService } from '../../../../helpers/mocks/service/mock-metis-service.service'; import { MetisService } from 'app/shared/metis/metis.service'; @@ -78,7 +78,7 @@ describe('PostComponent', () => { MockPipe(HtmlForMarkdownPipe), MockComponent(PostingHeaderComponent), MockComponent(PostingContentComponent), - MockComponent(PostFooterComponent), + MockComponent(PostingFooterComponent), MockComponent(AnswerPostCreateEditModalComponent), MockComponent(PostReactionsBarComponent), MockRouterLinkDirective, @@ -162,7 +162,7 @@ describe('PostComponent', () => { }); it('should contain a post footer', () => { - const footer = getElement(debugElement, 'jhi-post-footer'); + const footer = getElement(debugElement, 'jhi-posting-footer'); expect(footer).not.toBeNull(); }); diff --git a/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts b/src/test/javascript/spec/component/shared/metis/postings-footer/posting-footer.component.spec.ts similarity index 81% rename from src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts rename to src/test/javascript/spec/component/shared/metis/postings-footer/posting-footer.component.spec.ts index 353df5e83415..bca412741fba 100644 --- a/src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts +++ b/src/test/javascript/spec/component/shared/metis/postings-footer/posting-footer.component.spec.ts @@ -1,34 +1,34 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { PostFooterComponent } from 'app/shared/metis/posting-footer/post-footer/post-footer.component'; import { MockComponent, MockModule } from 'ng-mocks'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; -import { PostReactionsBarComponent } from 'app/shared/metis/posting-reactions-bar/post-reactions-bar/post-reactions-bar.component'; -import { ArtemisCoursesRoutingModule } from 'app/overview/courses-routing.module'; -import { MetisService } from 'app/shared/metis/metis.service'; -import { PostService } from 'app/shared/metis/post.service'; -import { MockPostService } from '../../../../../helpers/mocks/service/mock-post.service'; -import { AnswerPostService } from 'app/shared/metis/answer-post.service'; -import { MockAnswerPostService } from '../../../../../helpers/mocks/service/mock-answer-post.service'; -import { PostComponent } from 'app/shared/metis/post/post.component'; -import { AnswerPostComponent } from 'app/shared/metis/answer-post/answer-post.component'; -import { AnswerPostCreateEditModalComponent } from 'app/shared/metis/posting-create-edit-modal/answer-post-create-edit-modal/answer-post-create-edit-modal.component'; -import { TranslatePipeMock } from '../../../../../helpers/mocks/service/mock-translate.service'; -import { MockMetisService } from '../../../../../helpers/mocks/service/mock-metis-service.service'; -import { metisPostExerciseUser1, post, unsortedAnswerArray } from '../../../../../helpers/sample/metis-sample-data'; -import { AnswerPost } from 'app/entities/metis/answer-post.model'; -import { User } from 'app/core/user/user.model'; +import { PostReactionsBarComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-reactions-bar/post-reactions-bar/post-reactions-bar.component'; +import { ArtemisCoursesRoutingModule } from '../../../../../../../main/webapp/app/overview/courses-routing.module'; +import { MetisService } from '../../../../../../../main/webapp/app/shared/metis/metis.service'; +import { PostService } from '../../../../../../../main/webapp/app/shared/metis/post.service'; +import { MockPostService } from '../../../../helpers/mocks/service/mock-post.service'; +import { AnswerPostService } from '../../../../../../../main/webapp/app/shared/metis/answer-post.service'; +import { MockAnswerPostService } from '../../../../helpers/mocks/service/mock-answer-post.service'; +import { PostComponent } from '../../../../../../../main/webapp/app/shared/metis/post/post.component'; +import { AnswerPostComponent } from '../../../../../../../main/webapp/app/shared/metis/answer-post/answer-post.component'; +import { AnswerPostCreateEditModalComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-create-edit-modal/answer-post-create-edit-modal/answer-post-create-edit-modal.component'; +import { TranslatePipeMock } from '../../../../helpers/mocks/service/mock-translate.service'; +import { MockMetisService } from '../../../../helpers/mocks/service/mock-metis-service.service'; +import { metisPostExerciseUser1, post, unsortedAnswerArray } from '../../../../helpers/sample/metis-sample-data'; +import { AnswerPost } from '../../../../../../../main/webapp/app/entities/metis/answer-post.model'; +import { User } from '../../../../../../../main/webapp/app/core/user/user.model'; import dayjs from 'dayjs/esm'; import { Injector, input, runInInjectionContext } from '@angular/core'; -import { Posting } from 'app/entities/metis/posting.model'; +import { Posting } from '../../../../../../../main/webapp/app/entities/metis/posting.model'; +import { PostingFooterComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-footer/posting-footer.component'; interface PostGroup { author: User | undefined; posts: AnswerPost[]; } -describe('PostFooterComponent', () => { - let component: PostFooterComponent; - let fixture: ComponentFixture; +describe('PostingFooterComponent', () => { + let component: PostingFooterComponent; + let fixture: ComponentFixture; let metisService: MetisService; let metisServiceUserAuthorityStub: jest.SpyInstance; let injector: Injector; @@ -42,7 +42,7 @@ describe('PostFooterComponent', () => { { provide: MetisService, useClass: MockMetisService }, ], declarations: [ - PostFooterComponent, + PostingFooterComponent, TranslatePipeMock, MockComponent(FaIconComponent), MockComponent(PostReactionsBarComponent), @@ -53,7 +53,7 @@ describe('PostFooterComponent', () => { }) .compileComponents() .then(() => { - fixture = TestBed.createComponent(PostFooterComponent); + fixture = TestBed.createComponent(PostingFooterComponent); component = fixture.componentInstance; metisService = TestBed.inject(MetisService); metisServiceUserAuthorityStub = jest.spyOn(metisService, 'metisUserIsAtLeastTutorInCourse'); diff --git a/src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts b/src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts index b5a054b19cc2..7f8feb694917 100644 --- a/src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts +++ b/src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts @@ -6,7 +6,7 @@ import { ArtemisTranslatePipe } from '../../../../../../../main/webapp/app/share import { MockComponent, MockDirective, MockModule, MockPipe } from 'ng-mocks'; import { getElement } from '../../../../helpers/utils/general.utils'; import { MockMetisService } from '../../../../helpers/mocks/service/mock-metis-service.service'; -import { PostingHeaderComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-header/post-header/posting-header.component'; +import { PostingHeaderComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-header/posting-header.component'; import { ArtemisDatePipe } from '../../../../../../../main/webapp/app/shared/pipes/artemis-date.pipe'; import { PostCreateEditModalComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-create-edit-modal/post-create-edit-modal/post-create-edit-modal.component'; import { FormBuilder, FormsModule, ReactiveFormsModule } from '@angular/forms'; From 24fb4c41d1b8c908a821aa9b2b4c98bd996ec7a6 Mon Sep 17 00:00:00 2001 From: Asli Aykan Date: Mon, 9 Dec 2024 17:26:37 +0100 Subject: [PATCH 11/13] refactor --- .../metis/postings-footer/posting-footer.component.spec.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/test/javascript/spec/component/shared/metis/postings-footer/posting-footer.component.spec.ts b/src/test/javascript/spec/component/shared/metis/postings-footer/posting-footer.component.spec.ts index bca412741fba..dbabbe227ba8 100644 --- a/src/test/javascript/spec/component/shared/metis/postings-footer/posting-footer.component.spec.ts +++ b/src/test/javascript/spec/component/shared/metis/postings-footer/posting-footer.component.spec.ts @@ -21,11 +21,6 @@ import { Injector, input, runInInjectionContext } from '@angular/core'; import { Posting } from '../../../../../../../main/webapp/app/entities/metis/posting.model'; import { PostingFooterComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-footer/posting-footer.component'; -interface PostGroup { - author: User | undefined; - posts: AnswerPost[]; -} - describe('PostingFooterComponent', () => { let component: PostingFooterComponent; let fixture: ComponentFixture; From e6dab247b1035f969c56b7829ec68c5d6a15d955 Mon Sep 17 00:00:00 2001 From: Asli Aykan Date: Mon, 9 Dec 2024 17:33:22 +0100 Subject: [PATCH 12/13] add test --- .../postings-footer/posting-footer.component.spec.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/test/javascript/spec/component/shared/metis/postings-footer/posting-footer.component.spec.ts b/src/test/javascript/spec/component/shared/metis/postings-footer/posting-footer.component.spec.ts index dbabbe227ba8..71723d808309 100644 --- a/src/test/javascript/spec/component/shared/metis/postings-footer/posting-footer.component.spec.ts +++ b/src/test/javascript/spec/component/shared/metis/postings-footer/posting-footer.component.spec.ts @@ -208,4 +208,12 @@ describe('PostingFooterComponent', () => { expect(group3.posts).toContainEqual(expect.objectContaining({ id: post5.id })); }); }); + + it('should handle empty answer posts array', () => { + runInInjectionContext(injector, () => { + component.sortedAnswerPosts = input([]); + component.groupAnswerPosts(); + expect(component.groupedAnswerPosts).toHaveLength(0); + }); + }); }); From 38dcea4b4a8cf3eefc48c8fec4cab8f9b288aa9e Mon Sep 17 00:00:00 2001 From: Asli Aykan Date: Tue, 17 Dec 2024 00:37:08 +0300 Subject: [PATCH 13/13] update tests --- .../posting-footer.component.spec.ts | 30 +++++++++++-------- .../posting-header.component.spec.ts | 22 +++++++------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/test/javascript/spec/component/shared/metis/postings-footer/posting-footer.component.spec.ts b/src/test/javascript/spec/component/shared/metis/postings-footer/posting-footer.component.spec.ts index 71723d808309..ac3cf5dca9ce 100644 --- a/src/test/javascript/spec/component/shared/metis/postings-footer/posting-footer.component.spec.ts +++ b/src/test/javascript/spec/component/shared/metis/postings-footer/posting-footer.component.spec.ts @@ -1,25 +1,31 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MockComponent, MockModule } from 'ng-mocks'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; -import { PostReactionsBarComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-reactions-bar/post-reactions-bar/post-reactions-bar.component'; -import { ArtemisCoursesRoutingModule } from '../../../../../../../main/webapp/app/overview/courses-routing.module'; -import { MetisService } from '../../../../../../../main/webapp/app/shared/metis/metis.service'; -import { PostService } from '../../../../../../../main/webapp/app/shared/metis/post.service'; +import { PostReactionsBarComponent } from 'app/shared/metis/posting-reactions-bar/post-reactions-bar/post-reactions-bar.component'; +import { ArtemisCoursesRoutingModule } from 'app/overview/courses-routing.module'; +import { MetisService } from 'app/shared/metis/metis.service'; +import { PostService } from 'app/shared/metis/post.service'; import { MockPostService } from '../../../../helpers/mocks/service/mock-post.service'; -import { AnswerPostService } from '../../../../../../../main/webapp/app/shared/metis/answer-post.service'; +import { AnswerPostService } from 'app/shared/metis/answer-post.service'; import { MockAnswerPostService } from '../../../../helpers/mocks/service/mock-answer-post.service'; -import { PostComponent } from '../../../../../../../main/webapp/app/shared/metis/post/post.component'; -import { AnswerPostComponent } from '../../../../../../../main/webapp/app/shared/metis/answer-post/answer-post.component'; -import { AnswerPostCreateEditModalComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-create-edit-modal/answer-post-create-edit-modal/answer-post-create-edit-modal.component'; +import { PostComponent } from 'app/shared/metis/post/post.component'; +import { AnswerPostComponent } from 'app/shared/metis/answer-post/answer-post.component'; +import { AnswerPostCreateEditModalComponent } from 'app/shared/metis/posting-create-edit-modal/answer-post-create-edit-modal/answer-post-create-edit-modal.component'; import { TranslatePipeMock } from '../../../../helpers/mocks/service/mock-translate.service'; import { MockMetisService } from '../../../../helpers/mocks/service/mock-metis-service.service'; import { metisPostExerciseUser1, post, unsortedAnswerArray } from '../../../../helpers/sample/metis-sample-data'; -import { AnswerPost } from '../../../../../../../main/webapp/app/entities/metis/answer-post.model'; -import { User } from '../../../../../../../main/webapp/app/core/user/user.model'; +import { AnswerPost } from 'app/entities/metis/answer-post.model'; +import { User } from 'app/core/user/user.model'; import dayjs from 'dayjs/esm'; import { Injector, input, runInInjectionContext } from '@angular/core'; -import { Posting } from '../../../../../../../main/webapp/app/entities/metis/posting.model'; -import { PostingFooterComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-footer/posting-footer.component'; +import { Posting } from 'app/entities/metis/posting.model'; +import { PostingFooterComponent } from 'app/shared/metis/posting-footer/posting-footer.component'; +import { Post } from 'app/entities/metis/post.model'; + +interface PostGroup { + author: User | undefined; + posts: Post[]; +} describe('PostingFooterComponent', () => { let component: PostingFooterComponent; diff --git a/src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts b/src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts index 7f8feb694917..90e9ef796641 100644 --- a/src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts +++ b/src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts @@ -1,23 +1,23 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MetisService } from '../../../../../../../main/webapp/app/shared/metis/metis.service'; -import { MetisModule } from '../../../../../../../main/webapp/app/shared/metis/metis.module'; +import { MetisService } from 'app/shared/metis/metis.service'; +import { MetisModule } from 'app/shared/metis/metis.module'; import { DebugElement, Injector, input, runInInjectionContext } from '@angular/core'; -import { ArtemisTranslatePipe } from '../../../../../../../main/webapp/app/shared/pipes/artemis-translate.pipe'; +import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe'; import { MockComponent, MockDirective, MockModule, MockPipe } from 'ng-mocks'; import { getElement } from '../../../../helpers/utils/general.utils'; import { MockMetisService } from '../../../../helpers/mocks/service/mock-metis-service.service'; -import { PostingHeaderComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-header/posting-header.component'; -import { ArtemisDatePipe } from '../../../../../../../main/webapp/app/shared/pipes/artemis-date.pipe'; -import { PostCreateEditModalComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-create-edit-modal/post-create-edit-modal/post-create-edit-modal.component'; +import { PostingHeaderComponent } from 'app/shared/metis/posting-header/posting-header.component'; +import { ArtemisDatePipe } from 'app/shared/pipes/artemis-date.pipe'; +import { PostCreateEditModalComponent } from 'app/shared/metis/posting-create-edit-modal/post-create-edit-modal/post-create-edit-modal.component'; import { FormBuilder, FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { ConfirmIconComponent } from '../../../../../../../main/webapp/app/shared/confirm-icon/confirm-icon.component'; +import { ConfirmIconComponent } from 'app/shared/confirm-icon/confirm-icon.component'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; -import { PostingMarkdownEditorComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-markdown-editor/posting-markdown-editor.component'; -import { PostingButtonComponent } from '../../../../../../../main/webapp/app/shared/metis/posting-button/posting-button.component'; +import { PostingMarkdownEditorComponent } from 'app/shared/metis/posting-markdown-editor/posting-markdown-editor.component'; +import { PostingButtonComponent } from 'app/shared/metis/posting-button/posting-button.component'; import { metisPostExerciseUser1, metisPostLectureUser1, metisResolvingAnswerPostUser1, metisUser1 } from '../../../../helpers/sample/metis-sample-data'; -import { UserRole } from '../../../../../../../main/webapp/app/shared/metis/metis.util'; +import { UserRole } from 'app/shared/metis/metis.util'; import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap'; -import { AccountService } from '../../../../../../../main/webapp/app/core/auth/account.service'; +import { AccountService } from 'app/core/auth/account.service'; import { MockAccountService } from '../../../../helpers/mocks/service/mock-account.service'; import { ProfilePictureComponent } from 'app/shared/profile-picture/profile-picture.component'; import { Posting } from 'app/entities/metis/posting.model';