-
Notifications
You must be signed in to change notification settings - Fork 2
feat: implement UI to add experience to member #307 #830
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
base: main
Are you sure you want to change the base?
Changes from all commits
cc6818f
90c4c70
801e4cf
5c9fbff
adaf1d4
dafd0eb
a9cbdb8
70f4afe
25ef507
28024f6
397a0c9
3a2bd78
575fa42
c2677de
689c722
e8496c6
3c9b2a7
a6b2d1b
33a4139
f3ff0b0
9d52424
0cfe4ff
b5e2dc3
0476f1d
1c9bdcc
0ceb560
f6c257a
0f05c46
5ad63f4
cea759d
a5e14c8
ad882c1
f216586
43f7a8d
ffc0192
bec04b1
51a5561
13ed035
99a27cc
f70ab64
a38de50
38b0f09
7bbab3a
7e715f1
459d3b1
a8104db
bec460e
5be35c9
3448432
bcec3d9
338e76a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,170 @@ | ||
| import memberDetailPage from '../pages/memberDetailPage'; | ||
| import modalPage from '../pages/modalPage'; | ||
| import * as users from '../fixtures/users.json'; | ||
| import formPage from '../pages/formPage'; | ||
|
|
||
| describe('Add experience Modal', () => { | ||
| beforeEach(() => { | ||
| cy.loginAsUser(users.gl); | ||
| memberDetailPage.visit(1); | ||
| }); | ||
|
|
||
| const openExperienceModal = () => { | ||
| memberDetailPage.openModalButton('add', 'experience') | ||
| .click(); | ||
|
|
||
| modalPage.checkModalIconButtonVisible(); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this method not only checks if the button is visible but also whether the button is currently focused.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why was this resolved? |
||
| modalPage.checkModalIconButtonFocused(); | ||
| }; | ||
|
|
||
| it('should open correct modal', () => { | ||
| openExperienceModal(); | ||
|
|
||
| modalPage.modalTitle() | ||
| .should('include.text', 'Berufs- und Lebenserfahrung hinzufügen'); | ||
| }); | ||
|
|
||
| ['ENTER_ANOTHER', | ||
| 'COPY'].forEach((buttonType: string) => { | ||
| it(`should create experience via ${buttonType}`, () => { | ||
| cy.intercept('api/v1/experiences') | ||
| .as('experiences'); | ||
|
|
||
| openExperienceModal(); | ||
|
|
||
| formPage.submitButtonShouldBe('disabled'); | ||
|
|
||
| modalPage.modalTitle() | ||
| .should('include.text', 'Berufs- und Lebenserfahrung hinzufügen'); | ||
|
|
||
| modalPage.selectAutoCompleteValue('experienceType', 'Praktikum'); | ||
|
|
||
| formPage.typeAndBlur('startDate', '10.10.2023'); | ||
| formPage.typeAndBlur('endDate', '10.12.2027'); | ||
| formPage.typeAndBlur('name', 'Software Engineer'); | ||
| formPage.typeAndBlur('employer', 'TechNova Solutions'); | ||
| formPage.typeAndBlur('percent', '100'); | ||
| formPage.typeAndBlur('comment', 'Worked on backend APIs and DevOps tasks.'); | ||
|
|
||
| formPage.submitButtonShouldBe('enabled'); | ||
| formPage.clickSubmitMenuItem(buttonType); | ||
|
|
||
| formPage.shouldShowSuccessToast('Berufs- und Lebenserfahrung wurde erfolgreich erstellt.'); | ||
|
|
||
| cy.get('@experiences') | ||
| .then((interception) => { | ||
| expect(interception.request.body).to.contain({ | ||
| name: 'Software Engineer', | ||
| memberId: 1, | ||
| experienceTypeId: 1, | ||
| comment: 'Worked on backend APIs and DevOps tasks.', | ||
| percent: 100, | ||
| startDate: '2023-10-10', | ||
| endDate: '2027-12-10' | ||
| }); | ||
| }); | ||
|
|
||
| modalPage.checkModalIsClosed(); | ||
| }); | ||
| }); | ||
|
|
||
| describe('Validation Errors', () => { | ||
| beforeEach(() => { | ||
| openExperienceModal(); | ||
| }); | ||
|
|
||
| it('validates experience type requirement and input', () => { | ||
| formPage.submitButtonShouldBe('disabled'); | ||
|
|
||
| formPage.clearAndBlur('experienceType'); | ||
|
|
||
| formPage.shouldShowValidationError('Muss ausgefüllt sein', 'experienceType'); | ||
|
|
||
| formPage.typeAndBlur('experienceType', 'invalid entry'); | ||
|
|
||
| formPage.shouldShowValidationError('Ungültige Eingabe', 'experienceType'); | ||
| }); | ||
|
|
||
| const fields = { | ||
| startDate: ['Muss ausgefüllt sein', | ||
| 'Ungültiges Datum'], | ||
| endDate: ['Ungültiges Datum'] | ||
| }; | ||
|
|
||
| Object.entries(fields) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what is the benefit of using a a paramtrized test like this for 2 values?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The benefit is that we don’t have to write the same test twice. Both fields are tested with the same logic. If we add another field later, we only need to add it to the list. |
||
| .forEach(([fieldName, | ||
| errors]) => { | ||
| it(`shows error for invalid date in: ${fieldName}`, () => { | ||
| formPage.submitButtonShouldBe('disabled'); | ||
|
|
||
| formPage.typeAndBlur(fieldName, 'invalid entry'); | ||
|
|
||
| errors.forEach((error) => { | ||
| formPage.shouldShowValidationError(error, fieldName); | ||
| }); | ||
|
|
||
| formPage.submitButtonShouldBe('disabled'); | ||
| }); | ||
| }); | ||
|
|
||
| it('validates percent requirement and integer input', () => { | ||
| formPage.submitButtonShouldBe('disabled'); | ||
|
|
||
| formPage.typeAndBlur('percent', '0.9'); | ||
|
|
||
| formPage.shouldShowValidationError('Die Eingabe muss eine Ganzzahl sein', 'percent'); | ||
|
|
||
| formPage.submitButtonShouldBe('disabled'); | ||
| }); | ||
|
|
||
| it('validates percent maximum value', () => { | ||
| formPage.submitButtonShouldBe('disabled'); | ||
|
|
||
| formPage.typeAndBlur('percent', '130'); | ||
|
|
||
| formPage.shouldShowValidationError('Die Eingabe muss maximal 120 sein', 'percent'); | ||
|
|
||
| formPage.submitButtonShouldBe('disabled'); | ||
| }); | ||
| }); | ||
|
|
||
| describe('Error Toasts', () => { | ||
| beforeEach(() => { | ||
| openExperienceModal(); | ||
|
|
||
| formPage.submitButtonShouldBe('disabled'); | ||
| }); | ||
|
|
||
| it('should show error when startDate is after endDate', () => { | ||
| modalPage.selectAutoCompleteValue('experienceType', 'Praktikum'); | ||
|
|
||
| formPage.typeAndBlur('name', 'Software Engineer'); | ||
| formPage.typeAndBlur('employer', 'TechNova Solutions'); | ||
| formPage.typeAndBlur('percent', '100'); | ||
| formPage.typeAndBlur('startDate', '10.10.2000'); | ||
| formPage.typeAndBlur('endDate', '10.09.2000'); | ||
|
|
||
| formPage.submitButtonShouldBe('enabled'); | ||
|
|
||
| formPage.save(); | ||
|
|
||
| formPage.shouldShowErrorToast('Von mit dem Wert 2000-10-10 muss jünger sein als 2000-09-10.'); | ||
| }); | ||
| }); | ||
|
|
||
| describe('Closing Modal', () => { | ||
| beforeEach(() => { | ||
| openExperienceModal(); | ||
| }); | ||
|
|
||
| ['icon-button', | ||
| 'button'].forEach((buttonType: string) => { | ||
| it(`closes via ${buttonType}`, () => { | ||
|
Thirusiga marked this conversation as resolved.
|
||
| cy.getByTestId(`close-modal-${buttonType}`) | ||
| .click(); | ||
|
|
||
| modalPage.checkModalIsClosed(); | ||
| }); | ||
| }); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| <app-base-modal [formGroup]="formGroup" (canceled)="onCancel()"> | ||
| <app-base-form content [formGroup]="formGroup"> | ||
| <ng-container title/> | ||
| <ng-container content> | ||
|
|
||
| <app-input-field> | ||
| <input type="text" formControlName="experienceType" matInput [matAutocomplete]="experienceTypeAutoComplete" | ||
| data-testid="experienceType"> | ||
| <mat-autocomplete autoActiveFirstOption #experienceTypeAutoComplete="matAutocomplete" | ||
| [displayWith]="displayExperienceTypes"> | ||
| @for (experienceType of experienceTypeFilteredOptions(); track experienceType) { | ||
| <mat-option [value]="experienceType">{{ displayExperienceTypes(experienceType) }}</mat-option> | ||
| } | ||
| </mat-autocomplete> | ||
| </app-input-field> | ||
|
|
||
| <app-input-field> | ||
| <input type="text" formControlName="name" data-testid="name" matInput> | ||
| </app-input-field> | ||
|
|
||
| <app-input-field> | ||
| <input type="text" formControlName="employer" data-testid="employer" matInput> | ||
| </app-input-field> | ||
|
|
||
| <app-input-field> | ||
| <input type="number" formControlName="percent" data-testid="percent" matInput> | ||
| </app-input-field> | ||
|
Thirusiga marked this conversation as resolved.
|
||
|
|
||
| <mat-form-field> | ||
| <mat-label appPctsFormLabel/> | ||
| <input matInput [matDatepicker]="completedAtPicker" formControlName="startDate" data-testid="startDate"> | ||
| <mat-datepicker-toggle matIconSuffix [for]="completedAtPicker"/> | ||
| <mat-datepicker #completedAtPicker/> | ||
| <mat-error appPctsFormError/> | ||
| </mat-form-field> | ||
|
|
||
| <mat-form-field> | ||
| <mat-label appPctsFormLabel/> | ||
| <input matInput [matDatepicker]="validUntilPicker" formControlName="endDate" data-testid="endDate"> | ||
| <mat-datepicker-toggle matIconSuffix [for]="validUntilPicker"/> | ||
| <mat-datepicker #validUntilPicker/> | ||
| <mat-error appPctsFormError/> | ||
| </mat-form-field> | ||
|
|
||
| <app-input-field> | ||
| <textarea type="text" formControlName="comment" data-testid="comment" matInput></textarea> | ||
| </app-input-field> | ||
|
|
||
| </ng-container> | ||
| <ng-container actions/> | ||
| </app-base-form> | ||
|
|
||
| <ng-container actions> | ||
| <app-modal-actions | ||
| [isValid]="formGroup.valid" | ||
| (cancelAction)="onCancel()" | ||
| (submitAction)="onSubmit($event)" /> | ||
| </ng-container> | ||
| </app-base-modal> | ||
Uh oh!
There was an error while loading. Please reload this page.