-
Notifications
You must be signed in to change notification settings - Fork 297
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Development
: Migrate client code for posting header and footer components
#9932
base: develop
Are you sure you want to change the base?
Conversation
WalkthroughThe pull request introduces significant changes to the Angular components related to posting functionality. Key modifications include renaming components for clarity, such as changing Changes
Possibly related PRs
Suggested labels
Suggested reviewers
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🧹 Outside diff range and nitpick comments (6)
src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.html (2)
3-14
: Consider optimizing profile picture bindings with a local variable.While the implementation is correct, the multiple
posting()
function calls could be optimized by storing the author in a local variable.- @if (posting()?.author) { + @if (posting()?.author; as author) { <span class="d-inline-flex align-items-start gap-2 flex-wrap"> <jhi-profile-picture imageSizeInRem="2.15" fontSizeInRem="0.9" imageId="post-profile-picture" defaultPictureId="post-default-profile-picture" [isGray]="isDeleted()" - [authorId]="posting()?.author?.id" - [authorName]="posting()?.author?.name" - [imageUrl]="posting()?.author?.imageUrl" - [isEditable]="currentUser !== undefined && posting()?.author?.id === currentUser.id" + [authorId]="author.id" + [authorName]="author.name" + [imageUrl]="author.imageUrl" + [isEditable]="currentUser !== undefined && author.id === currentUser.id" >
33-34
: Consider extracting creation date to improve readability.While the implementation is correct, readability could be improved by storing the creation date in a local variable.
+ @if (posting()?.creationDate; as creationDate) { <span class="fs-small" [disableTooltip]="postingIsOfToday" - ngbTooltip="{{ posting()?.creationDate | artemisDate: 'time' }}"> + ngbTooltip="{{ creationDate | artemisDate: 'time' }}"> - {{ postingIsOfToday ? (posting()?.creationDate | artemisDate: 'time') : (posting()?.creationDate | artemisDate: 'short-date') }} + {{ postingIsOfToday ? (creationDate | artemisDate: 'time') : (creationDate | artemisDate: 'short-date') }} </span> + }src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts (1)
89-94
: Avoid mutating input properties directlyThe method should avoid mutating properties of
sortedAnswerPosts()
directly, as it may lead to unexpected side effects. Instead, create a copy before performing operations.Apply this diff to prevent direct mutation:
groupAnswerPosts(): void { if (!this.sortedAnswerPosts() || this.sortedAnswerPosts().length === 0) { this.groupedAnswerPosts = []; return; } - const sortedAnswerPosts = this.sortedAnswerPosts() + const sortedAnswerPosts = [...this.sortedAnswerPosts()] .reverse() .map((post) => { (post as any).creationDateDayjs = post.creationDate ? dayjs(post.creationDate) : undefined; return post; });src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.html (1)
Line range hint
1-28
: Methods used in template may cause performance issuesSeveral properties in the template are now invoked as functions (e.g.,
showAnswers()
,lastReadDate()
). Calling methods or getters in the template can lead to performance degradation due to frequent change detection. Consider using variables instead.Apply this diff to store function results in variables:
export class PostFooterComponent implements OnInit, OnDestroy, AfterContentChecked, OnChanges { + showAnswersValue = this.showAnswers(); + lastReadDateValue = this.lastReadDate(); + readOnlyModeValue = this.readOnlyMode(); + isCommunicationPageValue = this.isCommunicationPage(); + isThreadSidebarValue = this.isThreadSidebar(); + hasChannelModerationRightsValue = this.hasChannelModerationRights(); // ... } // In the template, use the variables instead of function calls @if (showAnswersValue) { <!-- ... --> <jhi-answer-post - [lastReadDate]="lastReadDate()" - [readOnlyMode]="readOnlyMode()" <!-- ... --> - [isCommunicationPage]="isCommunicationPage()" - [isThreadSidebar]="isThreadSidebar()" <!-- ... --> - [hasChannelModerationRights]="hasChannelModerationRights()" /> }src/test/javascript/spec/component/shared/metis/post/post.component.spec.ts (2)
8-8
: Consider using path aliases instead of relative pathsThe import path with multiple parent directory references (
../../../../../../../
) is fragile and hard to maintain. Consider using TypeScript path aliases to make imports more readable and maintainable.Example configuration in
tsconfig.json
:{ "compilerOptions": { "paths": { "@shared/*": ["src/main/webapp/app/shared/*"] } } }Then the import could be simplified to:
import { PostingHeaderComponent } from '@shared/metis/posting-header/post-header/posting-header.component';
Line range hint
84-359
: Consider organizing related test cases using describe blocksWhile the test cases are comprehensive and follow best practices, the readability could be improved by grouping related tests. Consider organizing the tests into logical describe blocks.
Example organization:
describe('PostComponent', () => { describe('Answer Management', () => { it('should sort answers', () => {/*...*/}); it('should not sort empty array of answers', () => {/*...*/}); }); describe('Navigation', () => { it('should set router link and query params', () => {/*...*/}); it('should navigate to channel when not on messaging page', () => {/*...*/}); // ... other navigation tests }); describe('User Interactions', () => { it('should open create answer post modal', () => {/*...*/}); it('should close create answer post modal', () => {/*...*/}); // ... other interaction tests }); // ... other test groups });
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
📒 Files selected for processing (16)
src/main/webapp/app/shared/metis/answer-post/answer-post.component.html
(1 hunks)src/main/webapp/app/shared/metis/metis.module.ts
(3 hunks)src/main/webapp/app/shared/metis/post/post.component.html
(1 hunks)src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.html
(3 hunks)src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts
(4 hunks)src/main/webapp/app/shared/metis/posting-footer/posting-footer.directive.ts
(0 hunks)src/main/webapp/app/shared/metis/posting-header/answer-post-header/answer-post-header.component.html
(0 hunks)src/main/webapp/app/shared/metis/posting-header/answer-post-header/answer-post-header.component.ts
(0 hunks)src/main/webapp/app/shared/metis/posting-header/post-header/post-header.component.ts
(0 hunks)src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.html
(2 hunks)src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.ts
(5 hunks)src/test/javascript/spec/component/shared/metis/post/post.component.spec.ts
(2 hunks)src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts
(5 hunks)src/test/javascript/spec/component/shared/metis/postings-header/answer-post-header/answer-post-header.component.spec.ts
(0 hunks)src/test/javascript/spec/component/shared/metis/postings-header/post-header/post-header.component.spec.ts
(0 hunks)src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts
(1 hunks)
💤 Files with no reviewable changes (6)
- src/main/webapp/app/shared/metis/posting-footer/posting-footer.directive.ts
- src/main/webapp/app/shared/metis/posting-header/answer-post-header/answer-post-header.component.html
- src/test/javascript/spec/component/shared/metis/postings-header/post-header/post-header.component.spec.ts
- src/main/webapp/app/shared/metis/posting-header/answer-post-header/answer-post-header.component.ts
- src/main/webapp/app/shared/metis/posting-header/post-header/post-header.component.ts
- src/test/javascript/spec/component/shared/metis/postings-header/answer-post-header/answer-post-header.component.spec.ts
🧰 Additional context used
📓 Path-based instructions (10)
src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.html (1)
Pattern src/main/webapp/**/*.html
: @if and @for are new and valid Angular syntax replacing *ngIf and *ngFor. They should always be used over the old style.
src/test/javascript/spec/component/shared/metis/post/post.component.spec.ts (1)
Pattern src/test/javascript/spec/**/*.ts
: jest: true; mock: NgMocks; bad_practices: avoid_full_module_import; perf_improvements: mock_irrelevant_deps; service_testing: mock_http_for_logic; no_schema: avoid_NO_ERRORS_SCHEMA; expectation_specificity: true; solutions: {boolean: toBeTrue/False, reference: toBe, existence: toBeNull/NotNull, undefined: toBeUndefined, class_obj: toContainEntries/toEqual, spy_calls: {not_called: not.toHaveBeenCalled, once: toHaveBeenCalledOnce, with_value: toHaveBeenCalledWith|toHaveBeenCalledExactlyOnceWith}}
src/main/webapp/app/shared/metis/metis.module.ts (1)
src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts (1)
Pattern src/test/javascript/spec/**/*.ts
: jest: true; mock: NgMocks; bad_practices: avoid_full_module_import; perf_improvements: mock_irrelevant_deps; service_testing: mock_http_for_logic; no_schema: avoid_NO_ERRORS_SCHEMA; expectation_specificity: true; solutions: {boolean: toBeTrue/False, reference: toBe, existence: toBeNull/NotNull, undefined: toBeUndefined, class_obj: toContainEntries/toEqual, spy_calls: {not_called: not.toHaveBeenCalled, once: toHaveBeenCalledOnce, with_value: toHaveBeenCalledWith|toHaveBeenCalledExactlyOnceWith}}
src/main/webapp/app/shared/metis/answer-post/answer-post.component.html (1)
Pattern src/main/webapp/**/*.html
: @if and @for are new and valid Angular syntax replacing *ngIf and *ngFor. They should always be used over the old style.
src/main/webapp/app/shared/metis/post/post.component.html (1)
Pattern src/main/webapp/**/*.html
: @if and @for are new and valid Angular syntax replacing *ngIf and *ngFor. They should always be used over the old style.
src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts (1)
Pattern src/test/javascript/spec/**/*.ts
: jest: true; mock: NgMocks; bad_practices: avoid_full_module_import; perf_improvements: mock_irrelevant_deps; service_testing: mock_http_for_logic; no_schema: avoid_NO_ERRORS_SCHEMA; expectation_specificity: true; solutions: {boolean: toBeTrue/False, reference: toBe, existence: toBeNull/NotNull, undefined: toBeUndefined, class_obj: toContainEntries/toEqual, spy_calls: {not_called: not.toHaveBeenCalled, once: toHaveBeenCalledOnce, with_value: toHaveBeenCalledWith|toHaveBeenCalledExactlyOnceWith}}
src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.html (1)
Pattern src/main/webapp/**/*.html
: @if and @for are new and valid Angular syntax replacing *ngIf and *ngFor. They should always be used over the old style.
src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.ts (1)
src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts (1)
📓 Learnings (1)
src/test/javascript/spec/component/shared/metis/post/post.component.spec.ts (1)
Learnt from: rabeatwork
PR: ls1intum/Artemis#9103
File: src/test/javascript/spec/component/shared/metis/postings-header/answer-post-header/answer-post-header.component.spec.ts:94-94
Timestamp: 2024-11-12T12:52:03.805Z
Learning: The `#today-flag` ID is only present in the test files and not in the actual component's HTML or TypeScript files.
🪛 Biome (1.9.4)
src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts
[error] 53-58: Disallow duplicate setup and teardown hooks.
Disallow beforeEach duplicacy inside the describe function.
(lint/suspicious/noDuplicateTestHooks)
🪛 GitHub Check: client-tests-selected
src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts
[failure] 150-150:
Property 'answers' does not exist on type 'InputSignal<Posting | undefined>'.
🪛 GitHub Check: client-tests
src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts
[failure] 150-150:
Property 'answers' does not exist on type 'InputSignal<Posting | undefined>'.
🔇 Additional comments (18)
src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.html (2)
Line range hint 18-24
: LGTM! Well-structured role badge implementation.
The implementation correctly handles translations, icons, and null safety.
37-43
: LGTM! Clean implementation of resolved post indicator.
The code correctly uses the new @if syntax and properly implements the icon with tooltip.
src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.ts (5)
1-31
: Use of Signals and Dependency Injection aligns with Angular 16 standards
The implementation properly utilizes Angular 16 features such as input
, output
, and inject
functions for signals and dependency injection. The input properties are correctly declared using input<T>()
, and services are injected using inject()
, promoting a modern and clean codebase.
70-73
: Type guard isPost
is correctly implemented
The isPost
function accurately acts as a type guard to differentiate between Post
and AnswerPost
instances, ensuring type safety when accessing properties specific to Post
.
74-77
: Getter isPostResolved
appropriately uses the type guard
The isPostResolved
getter method effectively utilizes the isPost
type guard to safely check the resolved
property of a Post
instance.
79-85
: Lifecycle hook ngOnChanges
correctly re-evaluates properties
The ngOnChanges
method properly calls setUserProperties()
and setUserAuthorityIconAndTooltip()
to update relevant properties when input bindings change, ensuring the component stays in sync with its inputs.
90-91
: Ensure all resources are cleaned up in ngOnDestroy
The ngOnDestroy
method correctly closes the modal if it is open. After addressing the subscription unsubscription issue, the component will properly clean up its resources upon destruction.
src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts (5)
1-9
: Update to Angular 16 injectables and input/output signals
The component correctly adopts Angular 16 standards by using inject
, input
, and output
functions for dependency injection and property bindings. This modernizes the component and aligns it with the latest Angular practices.
22-32
: Proper declaration of input and output properties using signals
The input and output properties are appropriately defined using input<T>()
and output<T>()
, enhancing reactivity and interoperability within the component.
47-48
: Services are correctly injected using inject
function
The MetisService
and ChangeDetectorRef
are injected using inject()
, aligning with Angular 16's improved dependency injection patterns.
83-85
: Ensure createEmptyAnswerPost
correctly initializes answerPost
The answerPost.post
assignment uses this.posting()
, which ensures the new answer post is associated with the correct post. This maintains the integrity of the data relationships.
89-102
: Efficient grouping and sorting of answer posts
The groupAnswerPosts
method efficiently reverses, maps, sorts, and groups the answer posts to optimize display logic. This implementation enhances performance and user experience.
src/main/webapp/app/shared/metis/metis.module.ts (2)
70-70
: Component declarations updated appropriately
The PostingHeaderComponent
is correctly declared and exported, replacing the AnswerPostHeaderComponent
and PostHeaderComponent
. This consolidation simplifies the module and reduces redundancy.
94-94
: Exports updated to include PostingHeaderComponent
The module exports are updated to include PostingHeaderComponent
, ensuring that it can be used across the application where needed.
src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts (1)
Line range hint 64-75
: LGTM: Well-structured test with proper initialization
The test case properly initializes the component within the Angular injection context and includes clear expectations.
src/main/webapp/app/shared/metis/post/post.component.html (1)
Line range hint 12-20
: LGTM: Clean component renaming and modern Angular syntax
The component has been correctly renamed from jhi-post-header
to jhi-posting-header
and uses proper input bindings. The template also effectively uses Angular 17's new control flow syntax.
src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts (1)
110-158
: LGTM: Well-structured parameterized tests
Excellent use of parameterized tests with it.each
to test different user roles and their corresponding icons and tooltips. This approach reduces code duplication and makes the test cases more maintainable.
src/test/javascript/spec/component/shared/metis/post/post.component.spec.ts (1)
72-74
: LGTM! Test setup follows best practices
The test module configuration correctly uses MockComponent
for dependencies and follows the testing guidelines.
src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.html
Show resolved
Hide resolved
src/main/webapp/app/shared/metis/posting-header/post-header/posting-header.component.ts
Show resolved
Hide resolved
src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.html
Show resolved
Hide resolved
...script/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts
Outdated
Show resolved
Hide resolved
...test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Outside diff range and nitpick comments (6)
src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts (2)
22-31
: Consider adding default values for all input signals.Some input signals like
lastReadDate
andposting
lack default values, which could lead to undefined behavior. Consider providing default values for all inputs.- lastReadDate = input<dayjs.Dayjs | undefined>(); + lastReadDate = input<dayjs.Dayjs | undefined>(undefined); - posting = input<Posting>(); + posting = input<Posting | undefined>(undefined);
Line range hint
94-107
: Fix type safety issues with creationDateDayjs property.Using
(post as any).creationDateDayjs
is unsafe. Consider creating an interface for the extended post type.+interface PostWithDayjs extends AnswerPost { + creationDateDayjs?: dayjs.Dayjs; +} - const sortedAnswerPosts = this.sortedAnswerPosts() + const sortedAnswerPosts: PostWithDayjs[] = this.sortedAnswerPosts() .slice() .reverse() .map((post) => { - (post as any).creationDateDayjs = post.creationDate ? dayjs(post.creationDate) : undefined; + const postWithDayjs: PostWithDayjs = { ...post }; + postWithDayjs.creationDateDayjs = post.creationDate ? dayjs(post.creationDate) : undefined; - return post; + return postWithDayjs; }); - const sortedPosts = sortedAnswerPosts.sort((a, b) => { - const aDate = (a as any).creationDateDayjs; - const bDate = (b as any).creationDateDayjs; + const sortedPosts = sortedAnswerPosts.sort((a, b) => { + const aDate = a.creationDateDayjs; + const bDate = b.creationDateDayjs; return aDate?.valueOf() - bDate?.valueOf(); });src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts (1)
79-84
: Add edge case tests for groupAnswerPosts.The current test only verifies that groups are created. Consider adding tests for:
- Empty array
- Single post
- Posts with same author but different timestamps
- Posts with missing creation dates
src/test/javascript/spec/component/shared/metis/answer-post/answer-post.component.spec.ts (1)
59-68
: Enhance header visibility test assertions.The test could be more specific about why the header should be visible when isConsecutive is false.
it('should contain the posting header when isConsecutive is false', () => { runInInjectionContext(fixture.debugElement.injector, () => { component.isConsecutive = input<boolean>(false); component.posting = metisResolvingAnswerPostUser1; }); fixture.detectChanges(); const header = debugElement.query(By.css('jhi-posting-header')); expect(header).not.toBeNull(); + // Verify header properties + const headerComponent = ngMocks.findInstance(header, PostingHeaderComponent); + expect(headerComponent.posting).toBe(metisResolvingAnswerPostUser1); });src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts (2)
169-178
: Enhance undefined posting test coverageWhile the test handles the basic undefined case, consider adding more assertions to verify the complete component state:
it('should handle undefined posting gracefully', () => { runInInjectionContext(injector, () => { component.posting = input<Posting>(); component.ngOnInit(); fixture.detectChanges(); expect(component.isPostResolved).toBeFalse(); expect(getElement(debugElement, '.resolved')).toBeNull(); + expect(component.userAuthorityIcon).toBeDefined(); + expect(component.userAuthorityTooltip).toBeDefined(); + expect(component.isAuthorOfPosting).toBeFalse(); + expect(getElement(debugElement, '#today-flag')).toBeNull(); + expect(getElement(debugElement, '#header-author-date')).not.toBeNull(); }); });
62-70
: Improve date-related test assertionsThe date-related tests could be more specific in their assertions to ensure the complete date handling logic:
it('should set date information correctly for post of today', () => { runInInjectionContext(injector, () => { component.posting = input<Posting>(metisPostLectureUser1); component.ngOnInit(); fixture.detectChanges(); expect(getElement(debugElement, '#today-flag')).toBeDefined(); + const headerDate = getElement(debugElement, '#header-author-date'); + expect(headerDate.textContent).toContain('artemisApp.metis.today'); }); }); 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<Posting>(pastDatePost); component.ngOnInit(); fixture.detectChanges(); expect(getElement(debugElement, '#today-flag')).toBeNull(); + const headerDate = getElement(debugElement, '#header-author-date'); + expect(headerDate.textContent).not.toContain('artemisApp.metis.today'); + expect(headerDate.textContent).toContain(pastDatePost.creationDate.toLocaleDateString()); }); });Also applies to: 72-84
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
📒 Files selected for processing (4)
src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts
(5 hunks)src/test/javascript/spec/component/shared/metis/answer-post/answer-post.component.spec.ts
(3 hunks)src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts
(5 hunks)src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
src/test/javascript/spec/component/shared/metis/answer-post/answer-post.component.spec.ts (1)
Pattern src/test/javascript/spec/**/*.ts
: jest: true; mock: NgMocks; bad_practices: avoid_full_module_import; perf_improvements: mock_irrelevant_deps; service_testing: mock_http_for_logic; no_schema: avoid_NO_ERRORS_SCHEMA; expectation_specificity: true; solutions: {boolean: toBeTrue/False, reference: toBe, existence: toBeNull/NotNull, undefined: toBeUndefined, class_obj: toContainEntries/toEqual, spy_calls: {not_called: not.toHaveBeenCalled, once: toHaveBeenCalledOnce, with_value: toHaveBeenCalledWith|toHaveBeenCalledExactlyOnceWith}}
src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts (1)
Pattern src/test/javascript/spec/**/*.ts
: jest: true; mock: NgMocks; bad_practices: avoid_full_module_import; perf_improvements: mock_irrelevant_deps; service_testing: mock_http_for_logic; no_schema: avoid_NO_ERRORS_SCHEMA; expectation_specificity: true; solutions: {boolean: toBeTrue/False, reference: toBe, existence: toBeNull/NotNull, undefined: toBeUndefined, class_obj: toContainEntries/toEqual, spy_calls: {not_called: not.toHaveBeenCalled, once: toHaveBeenCalledOnce, with_value: toHaveBeenCalledWith|toHaveBeenCalledExactlyOnceWith}}
src/test/javascript/spec/component/shared/metis/postings-footer/post-footer/post-footer.component.spec.ts (1)
Pattern src/test/javascript/spec/**/*.ts
: jest: true; mock: NgMocks; bad_practices: avoid_full_module_import; perf_improvements: mock_irrelevant_deps; service_testing: mock_http_for_logic; no_schema: avoid_NO_ERRORS_SCHEMA; expectation_specificity: true; solutions: {boolean: toBeTrue/False, reference: toBe, existence: toBeNull/NotNull, undefined: toBeUndefined, class_obj: toContainEntries/toEqual, spy_calls: {not_called: not.toHaveBeenCalled, once: toHaveBeenCalledOnce, with_value: toHaveBeenCalledWith|toHaveBeenCalledExactlyOnceWith}}
src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts (1)
📓 Learnings (1)
src/test/javascript/spec/component/shared/metis/answer-post/answer-post.component.spec.ts (1)
Learnt from: rabeatwork
PR: ls1intum/Artemis#9103
File: src/test/javascript/spec/component/shared/metis/postings-header/answer-post-header/answer-post-header.component.spec.ts:94-94
Timestamp: 2024-11-12T12:52:03.805Z
Learning: The `#today-flag` ID is only present in the test files and not in the actual component's HTML or TypeScript files.
🔇 Additional comments (3)
src/test/javascript/spec/component/shared/metis/postings-header/posting-header.component.spec.ts (3)
1-28
: LGTM: Import statements are well-organized and complete
The imports cover all necessary testing utilities, mock components/services, and models required for the test suite.
35-56
: Consolidate duplicate beforeEach blocks
The beforeEach blocks could be combined to improve readability and maintenance.
- 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;
- });
+ 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();
+
+ fixture = TestBed.createComponent(PostingHeaderComponent);
+ component = fixture.componentInstance;
+ debugElement = fixture.debugElement;
+ injector = fixture.debugElement.injector;
+ });
108-156
: LGTM: Comprehensive user role testing
The test cases for user roles are well-structured using Jest's parameterized testing feature. They thoroughly verify both the visual elements and component properties for different user roles.
src/main/webapp/app/shared/metis/posting-footer/post-footer/post-footer.component.ts
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested on TS5: Writing message, reply to message, mark as resolve, add reaction, edit message. All works as before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested in TS5, works as expected
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested on TS5 during testing session, I noticed this:
- The number of replies in the thread view does not update, it is stuck at 0 replies
- When sending a reply in the last thread of a conversation, sometimes the sent reply does not appear until refreshing the page or sending another reply. But this is not consistently reproducible, so may just be bad connection right now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested on TS5. Other than the problem Anian mentioned above, eveything else works fine
Checklist
General
Client
Motivation and Context
The
AnswerPostHeader
andPostHeader
components are almost identical, causing code duplication, and one of them needs to be removed.In this case, the
PostingHeaderDirective
would also be used for only a single component, making its existence redundant, and it should be removed as well.Similarly, the
AnswerPostFooter
component was previously removed due to duplication with thePostFooter
component. This means thePostingFooterDirective
is now being used for only one component and should also be removed to avoid unnecessary abstraction.Description
The
PostHeader
andAnswerPostHeader
components have been merged into a single component namedPostingHeaderComponent
.The
PostingHeaderDirective
andPostingFooterDirective
have been removed.The
PostingHeaderComponent
andPostFooterComponent
have been updated to use inject and signals.Tests have been updated accordingly.
Known issue: All signals, except those related to
@ViewChild
, have been updated. Updating viewChild requires making the components standalone, which I will address in a follow-up PR as it will impact other components.Steps for Testing
Prerequisites:
Testserver States
Note
These badges show the state of the test servers.
Green = Currently available, Red = Currently locked
Click on the badges to get to the test servers.
Review Progress
Code Review
Manual Tests
Test Coverage
Summary by CodeRabbit
Release Notes
New Features
PostingHeaderComponent
for improved clarity and functionality in post headers.<jhi-answer-post-header>
to<jhi-posting-header>
.Bug Fixes
PostingHeaderComponent
.Refactor
post-footer
andposting-header
components, improving code robustness.AnswerPostHeaderComponent
andPostHeaderComponent
.Tests
PostingHeaderComponent
, ensuring accurate rendering and behavior under various conditions.