-
Notifications
You must be signed in to change notification settings - Fork 158
test: extend Cypress coverage for dashboard pages #1513
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
Open
dcoric
wants to merge
10
commits into
finos:main
Choose a base branch
from
dcoric:feat/cypress
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
486e23b
feat: implement Cypress E2E test infrastructure and Phase 1 test cove…
dcoric c8b6fe6
test(cypress): expand cypress:run:docker specPattern to cover all E2E…
dcoric 5313cb9
fix: use isAdminUser helper in test routes to fix TypeScript error
dcoric 27cc39e
fix(cypress): remove TS syntax from .js files and fix git credentials
dcoric afc6f43
fix(cypress): fix TS syntax, git credentials, and add screenshots to …
dcoric 4ee3f5f
test(e2e): fix remaining failing Cypress tests across all specs
dcoric 5753520
fix(e2e): resolve all 9 remaining failing Cypress tests
dcoric 848401e
fix(ci): resolve Cypress PR check failures
dcoric 95f346e
fix(cypress): stabilize profile and auto-approved checks
dcoric d43f371
test: address Cypress PR feedback
dcoric File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -30,7 +30,6 @@ describe('Push Actions (Approve, Reject, Cancel)', () => { | |||||
| }; | ||||||
|
|
||||||
| before(() => { | ||||||
| // Setup: login as admin, create test users, assign permissions | ||||||
| cy.login('admin', 'admin'); | ||||||
|
|
||||||
| cy.createUser(testUser.username, testUser.password, testUser.email, testUser.gitAccount); | ||||||
|
|
@@ -49,10 +48,18 @@ describe('Push Actions (Approve, Reject, Cancel)', () => { | |||||
| cy.logout(); | ||||||
| }); | ||||||
|
|
||||||
| afterEach(() => { | ||||||
| afterEach(function () { | ||||||
|
Contributor
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. For consistency:
Suggested change
|
||||||
| if (this.pushId) { | ||||||
| cy.deleteTestPush(this.pushId); | ||||||
| } | ||||||
| cy.logout(); | ||||||
| }); | ||||||
|
|
||||||
| after(() => { | ||||||
| cy.deleteTestUser(testUser.username); | ||||||
| cy.deleteTestUser(approverUser.username); | ||||||
| }); | ||||||
|
|
||||||
| describe('Approve flow', () => { | ||||||
| beforeEach(() => { | ||||||
| const suffix = `approve-${Date.now()}`; | ||||||
|
|
@@ -63,43 +70,32 @@ describe('Push Actions (Approve, Reject, Cancel)', () => { | |||||
| cy.login(approverUser.username, approverUser.password); | ||||||
| cy.visit(`/dashboard/push/${this.pushId}`); | ||||||
|
|
||||||
| // Verify push is Pending | ||||||
| cy.get('[data-testid="push-status"]').should('contain', 'Pending'); | ||||||
|
|
||||||
| // Action buttons should be visible | ||||||
| cy.get('[data-testid="push-cancel-btn"]').should('be.visible'); | ||||||
| cy.get('[data-testid="push-reject-btn"]').should('be.visible'); | ||||||
| cy.get('[data-testid="attestation-open-btn"]').should('be.visible'); | ||||||
|
|
||||||
| // Open attestation dialog | ||||||
| cy.get('[data-testid="attestation-open-btn"]').click(); | ||||||
| cy.get('[data-testid="attestation-dialog"]').should('be.visible'); | ||||||
|
|
||||||
| // Confirm button should be disabled until all checkboxes are checked | ||||||
| cy.get('[data-testid="attestation-confirm-btn"]').should('be.disabled'); | ||||||
|
|
||||||
| // Check all attestation checkboxes | ||||||
| cy.get('[data-testid="attestation-dialog"]') | ||||||
| .find('input[type="checkbox"]') | ||||||
| .each(($checkbox) => { | ||||||
| cy.wrap($checkbox).check({ force: true }); | ||||||
| }); | ||||||
|
|
||||||
| // Confirm button should now be enabled | ||||||
| cy.get('[data-testid="attestation-confirm-btn"]').should('not.be.disabled'); | ||||||
|
|
||||||
| // Click confirm to approve | ||||||
| cy.get('[data-testid="attestation-confirm-btn"]').click(); | ||||||
|
|
||||||
| // Should navigate back to push list | ||||||
| cy.url().should('include', '/dashboard/push'); | ||||||
| cy.url().should('not.include', this.pushId); | ||||||
|
|
||||||
| // Verify push is now Approved by revisiting its detail page | ||||||
| cy.visit(`/dashboard/push/${this.pushId}`); | ||||||
| cy.get('[data-testid="push-status"]').should('contain', 'Approved'); | ||||||
|
|
||||||
| // Action buttons should no longer be visible for an approved push | ||||||
| cy.get('[data-testid="push-cancel-btn"]').should('not.exist'); | ||||||
| cy.get('[data-testid="push-reject-btn"]').should('not.exist'); | ||||||
| cy.get('[data-testid="attestation-open-btn"]').should('not.exist'); | ||||||
|
|
@@ -116,33 +112,22 @@ describe('Push Actions (Approve, Reject, Cancel)', () => { | |||||
| cy.login(approverUser.username, approverUser.password); | ||||||
| cy.visit(`/dashboard/push/${this.pushId}`); | ||||||
|
|
||||||
| // Verify push is Pending | ||||||
| cy.get('[data-testid="push-status"]').should('contain', 'Pending'); | ||||||
|
|
||||||
| // Open reject dialog | ||||||
| cy.get('[data-testid="push-reject-btn"]').click(); | ||||||
|
|
||||||
| // Confirm button should be disabled until reason is provided | ||||||
| cy.get('[data-testid="push-reject-confirm-btn"]').should('be.disabled'); | ||||||
|
|
||||||
| // Fill in rejection reason | ||||||
| cy.get('#reason').type('Rejecting for test purposes'); | ||||||
|
|
||||||
| // Confirm button should now be enabled | ||||||
| cy.get('[data-testid="push-reject-confirm-btn"]').should('not.be.disabled'); | ||||||
|
|
||||||
| // Confirm rejection | ||||||
| cy.get('[data-testid="push-reject-confirm-btn"]').click(); | ||||||
|
|
||||||
| // Should navigate back to push list | ||||||
| cy.url().should('include', '/dashboard/push'); | ||||||
| cy.url().should('not.include', this.pushId); | ||||||
|
|
||||||
| // Verify push is now Rejected | ||||||
| cy.visit(`/dashboard/push/${this.pushId}`); | ||||||
| cy.get('[data-testid="push-status"]').should('contain', 'Rejected'); | ||||||
|
|
||||||
| // Action buttons should no longer be visible | ||||||
| cy.get('[data-testid="push-cancel-btn"]').should('not.exist'); | ||||||
| cy.get('[data-testid="push-reject-btn"]').should('not.exist'); | ||||||
| cy.get('[data-testid="attestation-open-btn"]').should('not.exist'); | ||||||
|
|
@@ -156,24 +141,17 @@ describe('Push Actions (Approve, Reject, Cancel)', () => { | |||||
| }); | ||||||
|
|
||||||
| it('should cancel a pending push', function () { | ||||||
| // Cancel can be done by the push author | ||||||
| cy.login(testUser.username, testUser.password); | ||||||
| cy.visit(`/dashboard/push/${this.pushId}`); | ||||||
|
|
||||||
| // Verify push is Pending | ||||||
| cy.get('[data-testid="push-status"]').should('contain', 'Pending'); | ||||||
|
|
||||||
| // Click Cancel | ||||||
| cy.get('[data-testid="push-cancel-btn"]').click(); | ||||||
|
|
||||||
| // Should navigate back to push list | ||||||
| cy.url().should('include', '/dashboard/push'); | ||||||
|
|
||||||
| // Verify push is now Canceled | ||||||
| cy.visit(`/dashboard/push/${this.pushId}`); | ||||||
| cy.get('[data-testid="push-status"]').should('contain', 'Canceled'); | ||||||
|
|
||||||
| // Action buttons should no longer be visible | ||||||
| cy.get('[data-testid="push-cancel-btn"]').should('not.exist'); | ||||||
| cy.get('[data-testid="push-reject-btn"]').should('not.exist'); | ||||||
| cy.get('[data-testid="attestation-open-btn"]').should('not.exist'); | ||||||
|
|
@@ -187,17 +165,14 @@ describe('Push Actions (Approve, Reject, Cancel)', () => { | |||||
| }); | ||||||
|
|
||||||
| it('should not change push state when user lacks canAuthorise permission', function () { | ||||||
| // Login as testuser (has canPush but NOT canAuthorise) | ||||||
| cy.login(testUser.username, testUser.password); | ||||||
| cy.visit(`/dashboard/push/${this.pushId}`); | ||||||
|
|
||||||
| cy.get('[data-testid="push-status"]').should('contain', 'Pending'); | ||||||
|
|
||||||
| // Open attestation dialog and attempt to approve | ||||||
| cy.get('[data-testid="attestation-open-btn"]').click(); | ||||||
| cy.get('[data-testid="attestation-dialog"]').should('be.visible'); | ||||||
|
|
||||||
| // Check all checkboxes | ||||||
| cy.get('[data-testid="attestation-dialog"]') | ||||||
| .find('input[type="checkbox"]') | ||||||
| .each(($checkbox) => { | ||||||
|
|
@@ -206,10 +181,7 @@ describe('Push Actions (Approve, Reject, Cancel)', () => { | |||||
|
|
||||||
| cy.get('[data-testid="attestation-confirm-btn"]').click(); | ||||||
|
|
||||||
| // TODO: The server correctly returns 403 but the UI (src/ui/services/git-push.ts) | ||||||
| // only handles 401 errors in authorisePush/rejectPush. The 403 is silently | ||||||
| // ignored and the user is navigated away without feedback. Once the UI properly | ||||||
| // handles 403, this test should assert a snackbar error message is shown. | ||||||
| // TODO: Assert snackbar feedback when the UI handles 403 push action responses. | ||||||
| cy.visit(`/dashboard/push/${this.pushId}`); | ||||||
| cy.get('[data-testid="push-status"]').should('contain', 'Pending'); | ||||||
| }); | ||||||
|
|
@@ -222,17 +194,13 @@ describe('Push Actions (Approve, Reject, Cancel)', () => { | |||||
| }); | ||||||
|
|
||||||
| it('should not change push state when user lacks canAuthorise permission', function () { | ||||||
| // Login as testuser | ||||||
| cy.login(testUser.username, testUser.password); | ||||||
| cy.visit(`/dashboard/push/${this.pushId}`); | ||||||
|
|
||||||
| cy.get('[data-testid="push-status"]').should('contain', 'Pending'); | ||||||
|
|
||||||
| // Click Reject | ||||||
| cy.get('[data-testid="push-reject-btn"]').click(); | ||||||
|
|
||||||
| // TODO: Same issue as unauthorized approve — UI ignores 403 from server. | ||||||
| // Once fixed, assert snackbar error message is shown. | ||||||
| // TODO: Assert snackbar feedback when the UI handles 403 push action responses. | ||||||
| cy.visit(`/dashboard/push/${this.pushId}`); | ||||||
| cy.get('[data-testid="push-status"]').should('contain', 'Pending'); | ||||||
| }); | ||||||
|
|
@@ -250,18 +218,14 @@ describe('Push Actions (Approve, Reject, Cancel)', () => { | |||||
|
|
||||||
| cy.get('[data-testid="push-status"]').should('contain', 'Pending'); | ||||||
|
|
||||||
| // Open attestation dialog | ||||||
| cy.get('[data-testid="attestation-open-btn"]').click(); | ||||||
| cy.get('[data-testid="attestation-dialog"]').should('be.visible'); | ||||||
|
|
||||||
| // Click the dialog's Cancel button (NOT the push cancel button) | ||||||
| cy.get('[data-testid="attestation-cancel-btn"]').click(); | ||||||
|
|
||||||
| // Dialog should close, push should still be pending | ||||||
| cy.get('[data-testid="attestation-dialog"]').should('not.exist'); | ||||||
| cy.get('[data-testid="push-status"]').should('contain', 'Pending'); | ||||||
|
|
||||||
| // Action buttons should still be visible (push is still pending) | ||||||
| cy.get('[data-testid="push-cancel-btn"]').should('be.visible'); | ||||||
| cy.get('[data-testid="push-reject-btn"]').should('be.visible'); | ||||||
| cy.get('[data-testid="attestation-open-btn"]').should('be.visible'); | ||||||
|
|
||||||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| /** | ||
| * Copyright 2026 GitProxy Contributors | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| /** | ||
| * Error Pages | ||
| * Strategy: Direct navigation. No API needed. | ||
| */ | ||
| describe('Error Pages', () => { | ||
| beforeEach(() => { | ||
| cy.login('admin', 'admin'); | ||
| }); | ||
|
|
||
| afterEach(() => { | ||
| cy.logout(); | ||
| }); | ||
| it('Unknown route shows 404 page', () => { | ||
| cy.visit('/dashboard/nonexistent-page-xyz'); | ||
|
|
||
| cy.get('[data-testid="not-found-page"]').should('be.visible'); | ||
| cy.contains('404').should('be.visible'); | ||
| }); | ||
| it('Unauthorized route shows NotAuthorized page', () => { | ||
| const regularUser = { | ||
| username: `errorpage_user_${Date.now()}`, | ||
| password: 'pass123', | ||
| email: `errorpage_${Date.now()}@example.com`, | ||
| gitAccount: `errorpage_git_${Date.now()}`, | ||
| }; | ||
|
|
||
| cy.request({ | ||
| method: 'POST', | ||
| url: `${Cypress.env('API_BASE_URL') || Cypress.config('baseUrl')}/api/auth/create-user`, | ||
| body: regularUser, | ||
| failOnStatusCode: false, | ||
| }); | ||
|
|
||
| cy.clearCookies(); | ||
| cy.clearLocalStorage(); | ||
| cy.login(regularUser.username, regularUser.password); | ||
| cy.visit('/not-authorized'); | ||
|
|
||
| cy.get('[data-testid="not-authorized-page"]').should('be.visible'); | ||
| cy.contains('403').should('be.visible'); | ||
| cy.clearCookies(); | ||
| cy.deleteTestUser(regularUser.username); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| /** | ||
| * Copyright 2026 GitProxy Contributors | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| /** | ||
| * Navigation & Shell | ||
| * Strategy: Mix of real navigation and intercepts. | ||
| */ | ||
| describe('Navigation & Shell', () => { | ||
| beforeEach(() => { | ||
| cy.login('admin', 'admin'); | ||
| }); | ||
|
|
||
| afterEach(() => { | ||
| cy.logout(); | ||
| }); | ||
| it('Sidebar renders all visible links', () => { | ||
| cy.visit('/dashboard/repo'); | ||
| cy.contains('Repositories').should('be.visible'); | ||
| cy.contains('Dashboard').should('be.visible'); | ||
| }); | ||
| it('Sidebar links navigate correctly', () => { | ||
| cy.visit('/dashboard/repo'); | ||
| cy.contains('Dashboard').click(); | ||
| cy.url().should('include', '/dashboard/push'); | ||
| cy.contains('Repositories').click(); | ||
| cy.url().should('include', '/dashboard/repo'); | ||
| }); | ||
| it('Active sidebar item highlights', () => { | ||
| cy.visit('/dashboard/repo'); | ||
| cy.get('[aria-current="page"]').should('exist'); | ||
| }); | ||
| it('Navbar renders correctly', () => { | ||
| cy.visit('/dashboard/repo'); | ||
|
|
||
| cy.get('[data-testid="navbar"]').should('be.visible'); | ||
| }); | ||
| it('Footer renders', () => { | ||
| cy.visit('/dashboard/repo'); | ||
|
|
||
| cy.get('[data-testid="footer"]').should('exist'); | ||
| cy.get('[data-testid="footer"]').scrollIntoView(); | ||
| cy.get('[data-testid="footer"]').should('be.visible'); | ||
| }); | ||
| // NOTE: Keep unauthenticated checks outside the logged-in hooks. | ||
| it('/ redirects to /dashboard/repo', () => { | ||
| cy.logout(); | ||
| cy.visit('/'); | ||
| cy.url().should('match', /\/(login|dashboard)/); | ||
| }); | ||
| }); | ||
|
|
||
| describe('Unauthenticated access', () => { | ||
| it('Unauthenticated user is redirected to /login', () => { | ||
| Cypress.session.clearAllSavedSessions(); | ||
| cy.clearCookies(); | ||
| cy.clearLocalStorage(); | ||
|
|
||
| cy.visit('/dashboard/profile'); | ||
|
|
||
| cy.url().should('include', '/login'); | ||
| }); | ||
| }); |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
We may want to leave the TODO comments in this file - unless we're sure the action items have already been dealt with