Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,16 @@ <h3>{{ 'Candidates' | translate }}</h3>
<div>
@if (assignment?.candidates?.length) {
<div class="candidates-list">
<div class="candidate-sorting-buttons" *ngIf="assignmentCandidates.length > 1">
<button mat-button (click)="sortCandidatesByFirstName()">
<mat-icon>sort_by_alpha</mat-icon>
{{ 'Sort by first name' | translate }}
</button>
<button mat-button (click)="sortCandidatesByLastName()">
<mat-icon>sort_by_alpha</mat-icon>
{{ 'Sort by last name' | translate }}
</button>
</div>
<os-sorting-list
[count]="assignment.number_poll_candidates"
[enable]="hasPerms('manage')"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import {ComponentFixture, TestBed} from '@angular/core/testing';

import { AssignmentDetailComponent } from './assignment-detail.component';
import {AssignmentDetailComponent} from './assignment-detail.component';

import {ViewAssignmentCandidate} from "../../../../view-models";

xdescribe(`AssignmentDetailComponent`, () => {
let component: AssignmentDetailComponent;
Expand All @@ -21,4 +23,34 @@ xdescribe(`AssignmentDetailComponent`, () => {
it(`should create`, () => {
expect(component).toBeTruthy();
});

describe('candidate sorting', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't typically write tests for components (only services, pipes and the like). I don't even think we have any working component tests currently, not that we would be against getting one.
In any case, this test won't be called as long as the main test function (xdescribe('AssignmentDetailComponent', ...) is x-ed out.

So there's two choices right now:

  1. Reactivate the main test function, and make it run. You may have to mock quite a few things to do that though.
  2. Just delete your test, the chances that this test file will ever be re-activated are quite slim, after all.

I still reviewed your test code, just in case you want to go with option 1.

let candidates: ViewAssignmentCandidate[];
let onSortingChangeSpy: jasmine.Spy;

beforeEach(() => {
candidates = [
{user: {first_name: 'Karl', last_name: 'Marx'}, id: 1} as ViewAssignmentCandidate,
{user: {first_name: 'Rosa', last_name: 'Luxemburg'}, id: 2} as ViewAssignmentCandidate,
{user: {first_name: 'Kurt', last_name: 'Eisner'}, id: 3} as ViewAssignmentCandidate,
{user: {first_name: 'Clara', last_name: 'Zetkin'}, id: 4} as ViewAssignmentCandidate
Comment on lines +33 to +36
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests below assume 5 users, so one seems to be missing here.

];
(component as any)._assignmentCandidates = candidates;
onSortingChangeSpy = spyOn(component, 'onSortingChange').and.returnValue(Promise.resolve());
});

it('should sort candidates by first name', async () => {
await component.sortCandidatesByFirstName();
const sortedCandidates = onSortingChangeSpy.calls.mostRecent().args[0];
expect(sortedCandidates.map((c: ViewAssignmentCandidate) => c.user.first_name)).toEqual(['Clara', 'Karl', 'Karl', 'Kurt', 'Rosa']);
expect(sortedCandidates.map((c: ViewAssignmentCandidate) => c.user.last_name)).toEqual(['Zetkin', 'Liebknecht', 'Marx', 'Eisner', 'Luxemburg']);
Comment on lines +45 to +46
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
expect(sortedCandidates.map((c: ViewAssignmentCandidate) => c.user.first_name)).toEqual(['Clara', 'Karl', 'Karl', 'Kurt', 'Rosa']);
expect(sortedCandidates.map((c: ViewAssignmentCandidate) => c.user.last_name)).toEqual(['Zetkin', 'Liebknecht', 'Marx', 'Eisner', 'Luxemburg']);
expect(sortedCandidates.flatMap((c: ViewAssignmentCandidate) => [c.user.first_name, c.user.last_name])).toEqual(['Clara', 'Zetkin', 'Karl', 'Liebknecht', 'Karl', 'Marx', 'Kurt', 'Eisner', 'Rosa', 'Luxemburg']);

This is shorter. Should also be done for the other test.

});

it('should sort candidates by last name', async () => {
await component.sortCandidatesByLastName();
const sortedCandidates = onSortingChangeSpy.calls.mostRecent().args[0];
expect(sortedCandidates.map((c: ViewAssignmentCandidate) => c.user.last_name)).toEqual(['Eisner', 'Liebknecht', 'Luxemburg', 'Marx', 'Zetkin']);
expect(sortedCandidates.map((c: ViewAssignmentCandidate) => c.user.first_name)).toEqual(['Kurt', 'Karl', 'Rosa', 'Karl', 'Clara']);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,29 @@ export class AssignmentDetailComponent extends BaseMeetingComponent implements O
this.itemRepo.removeFromAgenda(this.assignment.agenda_item_id!);
}

/**
* Sorts the assignment candidates by their last name in ascending order.
* Calls onSortingChange with the sorted array.
*/
public async sortCandidatesByLastName(): Promise<void> {
const sorted = [...this.assignmentCandidates].sort((a, b) =>
a.user?.last_name?.localeCompare(b.user?.last_name ?? '') ?? 0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this'll sort particularly well if a has no last name, as it'll always treat it as if a and b had the same last name in that case, if it doesn't crash of course. Perhaps consider this:

Suggested change
a.user?.last_name?.localeCompare(b.user?.last_name ?? '') ?? 0
(a.user?.last_name ?? '').localeCompare(b.user?.last_name ?? '')

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for the function below. Also, since they're so similar, perhaps you could consider unifying them into a single function? Or maybe just join the first and last name with a ', ' for each user and then sort based on that. There is also the

There's also the question of what'll happen if there is neither first, nor last name. In that case the user will be shown as User <user id>, this case should also be taken into account.

The ParticipantListSortService from participant-list-sort.service.ts and its base class may serve as an inspiration.

);
await this.onSortingChange(sorted);
}

/**
* Sorts the assignment candidates by their first name in ascending order.
* Calls onSortingChange with the sorted array.
*/
public async sortCandidatesByFirstName(): Promise<void> {
const sorted = [...this.assignmentCandidates].sort((a, b) =>
a.user?.first_name?.localeCompare(b.user?.first_name ?? '') ?? 0
);
await this.onSortingChange(sorted);
}


public override ngOnDestroy(): void {
super.ngOnDestroy();
if (this._navigationSubscription) {
Expand All @@ -457,6 +480,6 @@ export class AssignmentDetailComponent extends BaseMeetingComponent implements O
}

public goToHistory(): void {
this.router.navigate([this.activeMeetingId!, `history`], { queryParams: { fqid: this.assignment.fqid } });
this.router.navigate([this.activeMeetingId!, `history`], {queryParams: {fqid: this.assignment.fqid}});
}
}
Loading