-
Notifications
You must be signed in to change notification settings - Fork 14
chore(tests): Code Viewer E2E Tests #107
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
vivjd
wants to merge
3
commits into
main
Choose a base branch
from
chore/code-viewer-e2e
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 1 commit
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
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
147 changes: 121 additions & 26 deletions
147
clean-architecture-visualizer/frontend/tests/e2e/code-viewer.spec.ts
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 |
|---|---|---|
| @@ -1,48 +1,143 @@ | ||
| import { test, expect } from '@playwright/test'; | ||
| import { test, expect, type Page } from '@playwright/test'; | ||
|
|
||
| test.describe('Code Viewer E2E', () => { | ||
| test.describe.configure({ mode: 'serial' }); | ||
| test.skip(({ browserName }) => browserName === 'firefox', 'Firefox is flaky in local dev server (NS_ERROR_NET_RESET).'); | ||
|
|
||
| const codeRoute = '/use-case/1/interaction/1/code'; | ||
|
|
||
| const loadingText = /^(loading|Loading\.\.\.)$/; | ||
| const errorLoadingText = /(errorLoading|Error loading file:)/; | ||
|
|
||
| const waitForCodeViewerToSettle = async (page: Page) => { | ||
| const main = page.getByRole('main'); | ||
| await expect(main.getByText(loadingText)).not.toBeVisible({ timeout: 20000 }); | ||
| }; | ||
|
|
||
| test('should expand folders, open a file, and render in Monaco', async ({ page }) => { | ||
| // 1. Navigate to the Code View | ||
| await page.goto('/use-case/1/interaction/1/code'); | ||
| // Navigate to the Code View | ||
| await page.goto(codeRoute, { waitUntil: 'domcontentloaded' }); | ||
|
|
||
| // 2. Expand 'interface_adapter' layer | ||
| const adapterFolder = page.getByText('interface_adapter', { exact: true }); | ||
| // Expand 'interface_adapter' layer | ||
|
vivjd marked this conversation as resolved.
|
||
| const adapterFolder = page.getByText('interface_adapters', { exact: true }); | ||
| await expect(adapterFolder).toBeVisible({ timeout: 15000 }); | ||
| await adapterFolder.click(); | ||
|
|
||
| // 3. Expand 'signup' subfolder | ||
| const signUpFolder = page.getByText('signup', { exact: true }); | ||
| await expect(signUpFolder).toBeVisible(); | ||
| await signUpFolder.click(); | ||
|
|
||
| // 4. Verify the file exists and the placeholder is still visible | ||
| const fileNode = page.getByText('SignupController.java', { exact: true }); | ||
| // Verify the file exists and the placeholder is still visible | ||
| const fileNode = page.getByText('UserSignOutController.java', { exact: true }); | ||
| await expect(fileNode).toBeVisible(); | ||
| await expect(page.getByText('selectFile')).toBeVisible(); | ||
|
|
||
| // 5. CLICK the file to open it | ||
| // CLICK the file to open it | ||
| await fileNode.click(); | ||
| await waitForCodeViewerToSettle(page); | ||
|
|
||
| // 6. Verify Monaco Editor replaces the placeholder | ||
| // 'selectFile' should now be gone | ||
| // Verify file viewer replaces the placeholder | ||
| await expect(page.getByText('selectFile')).not.toBeVisible(); | ||
|
|
||
| // Monaco creates a container with the class 'monaco-editor' | ||
| const monacoEditor = page.locator('.monaco-editor'); | ||
| await expect(monacoEditor).toBeVisible(); | ||
|
|
||
| // 7. Verify the editor contains code | ||
| // check for a common Java keyword that should be in the file | ||
| await expect(monacoEditor).toContainText('public class'); | ||
|
|
||
| // 8. Verify breadcrumbs update | ||
| await expect(page.getByText('SignupController.java')).toHaveCount(2); | ||
| // Verify breadcrumbs update | ||
| await expect(page.getByText('UserSignOutController.java')).toHaveCount(2); | ||
| }); | ||
|
vivjd marked this conversation as resolved.
|
||
|
|
||
| test('should navigate back using the diagram button', async ({ page }) => { | ||
| await page.goto('/use-case/1/interaction/1/code'); | ||
| await page.goto(codeRoute, { waitUntil: 'domcontentloaded' }); | ||
| await page.getByText('actions.backToDiagram').click(); | ||
| await expect(page).toHaveURL(/\/diagram/); | ||
| }); | ||
|
|
||
| test('should deep-link to a file from URL query and load Monaco immediately', async ({ page }) => { | ||
| await page.goto(`${codeRoute}?file=src%2Finterface_adapters%2FUserSignOutController.java`, { waitUntil: 'domcontentloaded' }); | ||
| await waitForCodeViewerToSettle(page); | ||
|
|
||
| await expect(page.getByText('UserSignOutController.java')).toHaveCount(2); | ||
| await expect(page).toHaveURL(/file=src%2Finterface_adapters%2FUserSignOutController.java/); | ||
| }); | ||
|
|
||
| test('should update URL query when selecting files and when going back to previous file', async ({ page }) => { | ||
| await page.goto(codeRoute, { waitUntil: 'domcontentloaded' }); | ||
|
|
||
| const adapterFolder = page.getByText('interface_adapters', { exact: true }); | ||
| await expect(adapterFolder).toBeVisible({ timeout: 15000 }); | ||
| await adapterFolder.click(); | ||
|
|
||
| const controllerFile = page.getByText('UserSignOutController.java', { exact: true }); | ||
| const presenterFile = page.getByText('UserSignOutPresenter.java', { exact: true }); | ||
| const backToPreviousButton = page.getByText('actions.backToPrevious'); | ||
|
|
||
| await controllerFile.click(); | ||
| await expect(page).toHaveURL(/file=src%2Finterface_adapters%2FUserSignOutController.java/); | ||
|
|
||
| await presenterFile.click(); | ||
| await expect(page).toHaveURL(/file=src%2Finterface_adapters%2FUserSignOutPresenter.java/); | ||
|
|
||
| await backToPreviousButton.click(); | ||
| await expect(page).toHaveURL(/file=src%2Finterface_adapters%2FUserSignOutController.java/); | ||
| }); | ||
|
|
||
| test('should keep Back to Previous disabled at history boundary', async ({ page }) => { | ||
| await page.goto(codeRoute, { waitUntil: 'domcontentloaded' }); | ||
|
|
||
| const adapterFolder = page.getByText('interface_adapters', { exact: true }); | ||
| await expect(adapterFolder).toBeVisible({ timeout: 15000 }); | ||
| await adapterFolder.click(); | ||
|
|
||
| const controllerFile = page.getByText('UserSignOutController.java', { exact: true }); | ||
| const presenterFile = page.getByText('UserSignOutPresenter.java', { exact: true }); | ||
| const backToPreviousButton = page.getByText('actions.backToPrevious'); | ||
|
|
||
| await expect(backToPreviousButton).toBeDisabled(); | ||
|
|
||
| await controllerFile.click(); | ||
| await expect(backToPreviousButton).toBeDisabled(); | ||
|
|
||
| await presenterFile.click(); | ||
| await expect(backToPreviousButton).toBeEnabled(); | ||
|
|
||
| await backToPreviousButton.click(); | ||
|
vivjd marked this conversation as resolved.
|
||
| await expect(page.getByText('UserSignOutController.java')).toHaveCount(2); | ||
| await expect(backToPreviousButton).toBeDisabled(); | ||
| }); | ||
|
|
||
| test('should show error state for an invalid file path from URL query', async ({ page }) => { | ||
| await page.goto(`${codeRoute}?file=src%2Fnonexistent%2FFoo.java`, { waitUntil: 'domcontentloaded' }); | ||
|
|
||
| await expect(page.getByText(errorLoadingText)).toBeVisible({ timeout: 20000 }); | ||
| }); | ||
|
|
||
| test('should navigate back to previous files after opening multiple files', async ({ page }) => { | ||
| await page.goto(codeRoute, { waitUntil: 'domcontentloaded' }); | ||
|
|
||
| const adapterFolder = page.getByText('interface_adapters', { exact: true }); | ||
| await expect(adapterFolder).toBeVisible({ timeout: 15000 }); | ||
| await adapterFolder.click(); | ||
|
|
||
| const controllerFile = page.getByText('UserSignOutController.java', { exact: true }); | ||
| const presenterFile = page.getByText('UserSignOutPresenter.java', { exact: true }); | ||
| const viewModelFile = page.getByText('UserSignOutViewModel.java', { exact: true }); | ||
| const backToPreviousButton = page.getByText('actions.backToPrevious'); | ||
|
|
||
| await expect(backToPreviousButton).toBeDisabled(); | ||
|
|
||
| await controllerFile.click(); | ||
| await waitForCodeViewerToSettle(page); | ||
| await expect(page).toHaveURL(/file=src%2Finterface_adapters%2FUserSignOutController.java/); | ||
|
|
||
| await presenterFile.click(); | ||
| await waitForCodeViewerToSettle(page); | ||
| await expect(page).toHaveURL(/file=src%2Finterface_adapters%2FUserSignOutPresenter.java/); | ||
| await expect(backToPreviousButton).toBeEnabled(); | ||
|
|
||
| await viewModelFile.click(); | ||
| await waitForCodeViewerToSettle(page); | ||
| await expect(page).toHaveURL(/file=src%2Finterface_adapters%2FUserSignOutViewModel.java/); | ||
|
|
||
| await backToPreviousButton.click(); | ||
| await waitForCodeViewerToSettle(page); | ||
| await expect(page).toHaveURL(/file=src%2Finterface_adapters%2FUserSignOutPresenter.java/); | ||
|
|
||
| await backToPreviousButton.click(); | ||
| await waitForCodeViewerToSettle(page); | ||
| await expect(page).toHaveURL(/file=src%2Finterface_adapters%2FUserSignOutController.java/); | ||
| await expect(backToPreviousButton).toBeDisabled(); | ||
| }); | ||
| }); | ||
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.
Uh oh!
There was an error while loading. Please reload this page.