-
Notifications
You must be signed in to change notification settings - Fork 5
chore: add all missing tests for backstage-plugin-coder #101
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
Merged
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
003f55e
fix: make sure auth form has accessible name
Parkreiner 6640934
refactor: update how mock workspace data is defined
Parkreiner 2b03e22
chore: finish first search test
Parkreiner 4100343
chore: finish test for querying
Parkreiner 71a4539
wip: commit progress on last test
Parkreiner 768b0fc
fix: finalize tests
Parkreiner 4d942b6
refactor: rename variable for clarity
Parkreiner 09af33c
chore: finish all network-based tests
Parkreiner 286cf26
docs: add comment for clarity
Parkreiner 9f826d5
chore: add one extra test case for failing to find results
Parkreiner 401e0d3
refactor: consolidate regex logic
Parkreiner 6757729
refactor: make test logic a little more clear
Parkreiner 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
178 changes: 178 additions & 0 deletions
178
...ns/backstage-plugin-coder/src/components/CoderWorkspacesCard/CoderWorkspacesCard.test.tsx
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,178 @@ | ||
/** | ||
* @file Defines integration tests for all sub-components in the | ||
* CoderWorkspacesCard directory. | ||
*/ | ||
import React from 'react'; | ||
import { screen, waitFor } from '@testing-library/react'; | ||
import { renderInCoderEnvironment } from '../../testHelpers/setup'; | ||
import { mockAuthStates } from '../../testHelpers/mockBackstageData'; | ||
import { | ||
mockWorkspaceNoParameters, | ||
mockWorkspaceWithMatch2, | ||
mockWorkspacesList, | ||
} from '../../testHelpers/mockCoderAppData'; | ||
import { type CoderAuthStatus } from '../CoderProvider'; | ||
import { CoderWorkspacesCard } from './CoderWorkspacesCard'; | ||
import userEvent from '@testing-library/user-event'; | ||
|
||
type RenderInputs = Readonly<{ | ||
authStatus?: CoderAuthStatus; | ||
readEntityData?: boolean; | ||
}>; | ||
|
||
function renderWorkspacesCard(input?: RenderInputs) { | ||
const { authStatus = 'authenticated', readEntityData = false } = input ?? {}; | ||
|
||
return renderInCoderEnvironment({ | ||
auth: mockAuthStates[authStatus], | ||
children: <CoderWorkspacesCard readEntityData={readEntityData} />, | ||
}); | ||
} | ||
|
||
const matchers = { | ||
authenticationForm: /Authenticate with Coder/i, | ||
searchTitle: /Coder Workspaces/i, | ||
searchbox: /Search your Coder workspaces/i, | ||
emptyState: /Use the search bar to find matching Coder workspaces/i, | ||
} as const satisfies Record<string, RegExp>; | ||
|
||
describe(`${CoderWorkspacesCard.name}`, () => { | ||
describe('General behavior', () => { | ||
it('Shows the authentication form when the user is not authenticated', async () => { | ||
await renderWorkspacesCard({ | ||
authStatus: 'tokenMissing', | ||
}); | ||
|
||
expect(() => { | ||
screen.getByRole('form', { name: matchers.authenticationForm }); | ||
}).not.toThrow(); | ||
}); | ||
|
||
it('Shows the workspaces list when the user is authenticated (exposed as an accessible search landmark)', async () => { | ||
await renderWorkspacesCard(); | ||
|
||
await waitFor(() => { | ||
expect(() => { | ||
screen.getByRole('search', { name: matchers.searchTitle }); | ||
}).not.toThrow(); | ||
}); | ||
}); | ||
|
||
it('Shows zero workspaces when the query text matches nothing', async () => { | ||
const entityValues = [true, false] as const; | ||
const user = userEvent.setup(); | ||
|
||
for (const value of entityValues) { | ||
const { unmount } = await renderWorkspacesCard({ | ||
readEntityData: value, | ||
}); | ||
|
||
const searchbox = await screen.findByRole('searchbox', { | ||
name: matchers.searchbox, | ||
}); | ||
|
||
await user.tripleClick(searchbox); | ||
await user.keyboard('[Backspace]'); | ||
await user.keyboard('I can do it - I can do it nine times'); | ||
|
||
await waitFor(() => { | ||
// getAllByRole will throw if there isn't at least one node matched | ||
const listItems = screen.queryAllByRole('listitem'); | ||
expect(listItems.length).toBe(0); | ||
}); | ||
|
||
unmount(); | ||
} | ||
}); | ||
}); | ||
|
||
describe('With readEntityData set to false', () => { | ||
it('Will NOT filter any workspaces by the current repo', async () => { | ||
await renderWorkspacesCard({ readEntityData: false }); | ||
const workspaceItems = await screen.findAllByRole('listitem'); | ||
expect(workspaceItems.length).toEqual(mockWorkspacesList.length); | ||
}); | ||
|
||
it('Lets the user filter the workspaces by their query text', async () => { | ||
await renderWorkspacesCard({ readEntityData: false }); | ||
const searchbox = await screen.findByRole('searchbox', { | ||
name: matchers.searchbox, | ||
}); | ||
|
||
const user = userEvent.setup(); | ||
await user.tripleClick(searchbox); | ||
await user.keyboard(mockWorkspaceNoParameters.name); | ||
|
||
// If more than one workspace matches, that throws an error | ||
const onlyWorkspace = await screen.findByRole('listitem'); | ||
expect(onlyWorkspace).toHaveTextContent(mockWorkspaceNoParameters.name); | ||
}); | ||
|
||
it('Shows all workspaces when query text is empty', async () => { | ||
await renderWorkspacesCard({ readEntityData: false }); | ||
const searchbox = await screen.findByRole('searchbox', { | ||
name: matchers.searchbox, | ||
}); | ||
|
||
const user = userEvent.setup(); | ||
await user.tripleClick(searchbox); | ||
await user.keyboard('[Backspace]'); | ||
|
||
const allWorkspaces = await screen.findAllByRole('listitem'); | ||
expect(allWorkspaces.length).toEqual(mockWorkspacesList.length); | ||
}); | ||
}); | ||
|
||
describe('With readEntityData set to true', () => { | ||
it('Will show only the workspaces that match the current repo', async () => { | ||
await renderWorkspacesCard({ readEntityData: true }); | ||
const workspaceItems = await screen.findAllByRole('listitem'); | ||
expect(workspaceItems.length).toEqual(2); | ||
}); | ||
|
||
it('Lets the user filter the workspaces by their query text (on top of filtering from readEntityData)', async () => { | ||
await renderWorkspacesCard({ readEntityData: true }); | ||
|
||
await waitFor(() => { | ||
const workspaceItems = screen.getAllByRole('listitem'); | ||
expect(workspaceItems.length).toBe(2); | ||
}); | ||
|
||
const user = userEvent.setup(); | ||
const searchbox = await screen.findByRole('searchbox', { | ||
name: matchers.searchbox, | ||
}); | ||
|
||
await user.tripleClick(searchbox); | ||
await user.keyboard(mockWorkspaceWithMatch2.name); | ||
|
||
await waitFor(() => { | ||
const newWorkspaceItems = screen.getAllByRole('listitem'); | ||
expect(newWorkspaceItems.length).toBe(1); | ||
}); | ||
}); | ||
|
||
/** | ||
* 2024-03-28 - MES - This is a test case to account for a previous | ||
* limitation around querying workspaces by repo URL. | ||
* | ||
* This limitation no longer exists, so this test should be removed once the | ||
* rest of the codebase is updated to support the new API endpoint for | ||
* searching by build parameter | ||
*/ | ||
it('Will not show any workspaces at all when the query text is empty', async () => { | ||
await renderWorkspacesCard({ readEntityData: true }); | ||
|
||
const user = userEvent.setup(); | ||
const searchbox = await screen.findByRole('searchbox', { | ||
name: matchers.searchbox, | ||
}); | ||
|
||
await user.tripleClick(searchbox); | ||
await user.keyboard('[Backspace]'); | ||
|
||
const emptyState = await screen.findByText(matchers.emptyState); | ||
expect(emptyState).toBeInTheDocument(); | ||
}); | ||
}); | ||
}); |
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 |
---|---|---|
|
@@ -3,6 +3,10 @@ import { useCoderWorkspacesQuery } from './useCoderWorkspacesQuery'; | |
|
||
import { renderHookAsCoderEntity } from '../testHelpers/setup'; | ||
import { mockCoderWorkspacesConfig } from '../testHelpers/mockBackstageData'; | ||
import { | ||
mockWorkspaceNoParameters, | ||
mockWorkspacesList, | ||
} from '../testHelpers/mockCoderAppData'; | ||
|
||
beforeAll(() => { | ||
jest.useFakeTimers(); | ||
|
@@ -38,12 +42,22 @@ describe(`${useCoderWorkspacesQuery.name}`, () => { | |
await jest.advanceTimersByTimeAsync(10_000); | ||
}); | ||
|
||
/* eslint-disable-next-line jest/no-disabled-tests -- | ||
Putting this off for the moment, because figuring out how to mock this out | ||
without making the code fragile/flaky will probably take some time | ||
*/ | ||
it.skip('Will filter workspaces by search criteria when it is provided', async () => { | ||
expect.hasAssertions(); | ||
it('Will filter workspaces by search criteria when it is provided', async () => { | ||
const { result, rerender } = await renderHookAsCoderEntity( | ||
({ coderQuery }) => useCoderWorkspacesQuery({ coderQuery }), | ||
{ initialProps: { coderQuery: 'owner:me' } }, | ||
); | ||
|
||
await waitFor(() => { | ||
expect(result.current.data?.length).toEqual(mockWorkspacesList.length); | ||
}); | ||
|
||
rerender({ coderQuery: mockWorkspaceNoParameters.name }); | ||
|
||
await waitFor(() => { | ||
const firstItemName = result.current.data?.[0]?.name; | ||
expect(firstItemName).toBe(mockWorkspaceNoParameters.name); | ||
}); | ||
}); | ||
|
||
it('Will only return workspaces for a given repo when a repoConfig is provided', async () => { | ||
|
@@ -54,12 +68,7 @@ describe(`${useCoderWorkspacesQuery.name}`, () => { | |
}); | ||
}); | ||
|
||
// This query takes a little bit longer to run and process; waitFor will | ||
// almost always give up too early if a longer timeout isn't specified | ||
await waitFor(() => expect(result.current.status).toBe('success'), { | ||
timeout: 3_000, | ||
}); | ||
|
||
expect(result.current.data?.length).toBe(1); | ||
await waitFor(() => expect(result.current.status).toBe('success')); | ||
expect(result.current.data?.length).toBe(2); | ||
Comment on lines
+71
to
+72
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. With the updated test helpers, I don't think the old comment applies anymore |
||
}); | ||
}); |
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.
This was missing from the component before – has two purposes: