@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { screen } from '@testing-library/react'; | |||
import { act, screen, waitFor } from '@testing-library/react'; | |||
import React from 'react'; | |||
import { addGlobalErrorMessage, addGlobalSuccessMessage } from '../../../helpers/globalMessages'; | |||
import { renderApp } from '../../../helpers/testReactTestingUtils'; | |||
@@ -32,22 +32,28 @@ it('should display messages', async () => { | |||
// we render anything, the GlobalMessageContainer is rendered independently from routing | |||
renderApp('sonarqube', <NullComponent />); | |||
addGlobalErrorMessage('This is an error'); | |||
addGlobalSuccessMessage('This was a triumph!'); | |||
await waitFor(() => { | |||
addGlobalErrorMessage('This is an error'); | |||
addGlobalSuccessMessage('This was a triumph!'); | |||
}); | |||
expect(await screen.findByRole('alert')).toHaveTextContent('This is an error'); | |||
expect(screen.getByRole('status')).toHaveTextContent('This was a triumph!'); | |||
// No duplicate message | |||
addGlobalErrorMessage('This is an error'); | |||
await waitFor(() => { | |||
addGlobalErrorMessage('This is an error'); | |||
}); | |||
expect(screen.getByRole('alert')).toHaveTextContent(/^This is an error$/); | |||
addGlobalSuccessMessage('This was a triumph!'); | |||
await waitFor(() => { | |||
addGlobalSuccessMessage('This was a triumph!'); | |||
}); | |||
expect(await screen.findByRole('status')).toHaveTextContent( | |||
/^This was a triumph!This was a triumph!$/, | |||
); | |||
jest.runAllTimers(); | |||
act(() => { | |||
jest.runAllTimers(); | |||
}); | |||
expect(screen.queryByRole('alert')).not.toBeInTheDocument(); | |||
expect(screen.queryByRole('status')).not.toBeInTheDocument(); | |||
@@ -172,11 +172,11 @@ it('should handle a currentUser not logged in', () => { | |||
locationMock.mockRestore(); | |||
}); | |||
it('should render the top menu', () => { | |||
it('should render the top menu', async () => { | |||
const name = 'Tyler Durden'; | |||
renderAccountApp(mockLoggedInUser({ name })); | |||
expect(screen.getByText(name)).toBeInTheDocument(); | |||
expect(await screen.findByText(name)).toBeInTheDocument(); | |||
const topMenuNavigationItems = [ | |||
'my_account.profile', | |||
@@ -190,7 +190,7 @@ it('should render the top menu', () => { | |||
}); | |||
describe('profile page', () => { | |||
it('should display all the information', () => { | |||
it('should display all the information', async () => { | |||
const loggedInUser = mockLoggedInUser({ | |||
email: 'email@company.com', | |||
groups: ['group1'], | |||
@@ -198,10 +198,10 @@ describe('profile page', () => { | |||
}); | |||
renderAccountApp(loggedInUser); | |||
expect(await screen.findByText('group1')).toBeInTheDocument(); | |||
expect(screen.getByText('account1')).toBeInTheDocument(); | |||
expect(screen.getAllByText(loggedInUser.login)).toHaveLength(2); | |||
expect(screen.getAllByText(loggedInUser.email!)).toHaveLength(2); | |||
expect(screen.getByText('group1')).toBeInTheDocument(); | |||
expect(screen.getByText('account1')).toBeInTheDocument(); | |||
}); | |||
it('should handle missing info', () => { | |||
@@ -392,7 +392,7 @@ describe('security page', () => { | |||
).not.toBeInTheDocument(); | |||
}); | |||
it("should not suggest creating a Project token if the user doesn't have at least one scannable Projects", () => { | |||
it("should not suggest creating a Project token if the user doesn't have at least one scannable Projects", async () => { | |||
jest.mocked(getScannableProjects).mockResolvedValueOnce({ | |||
projects: [], | |||
}); | |||
@@ -401,7 +401,9 @@ describe('security page', () => { | |||
securityPagePath, | |||
); | |||
selectEvent.openMenu(screen.getByRole('combobox', { name: 'users.tokens.type' })); | |||
await waitFor(() => { | |||
selectEvent.openMenu(screen.getByRole('combobox', { name: 'users.tokens.type' })); | |||
}); | |||
expect(screen.queryByText(`users.tokens.${TokenType.Project}`)).not.toBeInTheDocument(); | |||
}); | |||
@@ -429,9 +431,11 @@ describe('security page', () => { | |||
securityPagePath, | |||
); | |||
await selectEvent.select(screen.getByRole('combobox', { name: 'users.tokens.type' }), [ | |||
`users.tokens.${TokenType.Project}`, | |||
]); | |||
await waitFor(async () => { | |||
await selectEvent.select(screen.getByRole('combobox', { name: 'users.tokens.type' }), [ | |||
`users.tokens.${TokenType.Project}`, | |||
]); | |||
}); | |||
expect(screen.getByText('Project Name 1')).toBeInTheDocument(); | |||
}); |
@@ -172,7 +172,8 @@ export default class ProjectModal extends React.PureComponent<Props, State> { | |||
}); | |||
}; | |||
handleSubmit = () => { | |||
handleSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => { | |||
event.preventDefault(); | |||
const { selectedProject } = this.state; | |||
if (selectedProject) { |
@@ -310,7 +310,7 @@ describe('navigation', () => { | |||
await user.click(ui.maintainabilityDomainBtn.get()); | |||
await user.click(ui.measureBtn('Code Smells 8').get()); | |||
await ui.changeViewToList(); | |||
await waitFor(() => ui.changeViewToList()); | |||
expect( | |||
within(await ui.measuresRow('out.tsx').find()).getByRole('cell', { name: '1' }), | |||
@@ -330,7 +330,7 @@ describe('navigation', () => { | |||
await user.click(ui.maintainabilityDomainBtn.get()); | |||
await user.click(ui.measureBtn('Maintainability Rating metric.has_rating_X.E').get()); | |||
await ui.changeViewToTreeMap(); | |||
await waitFor(() => ui.changeViewToTreeMap()); | |||
expect(await ui.treeMapCell(/folderA/).find()).toBeInTheDocument(); | |||
expect(ui.treeMapCell(/test1\.js/).get()).toBeInTheDocument(); |
@@ -52,9 +52,9 @@ it('should be able to delete project', async () => { | |||
expect(byText('deletion.page').get()).toBeInTheDocument(); | |||
expect(byText('project_deletion.page.description').get()).toBeInTheDocument(); | |||
user.click(byRole('button', { name: 'delete' }).get()); | |||
await user.click(byRole('button', { name: 'delete' }).get()); | |||
expect(await byRole('dialog', { name: 'qualifier.delete.TRK' }).find()).toBeInTheDocument(); | |||
user.click( | |||
await user.click( | |||
byRole('dialog', { name: 'qualifier.delete.TRK' }).byRole('button', { name: 'delete' }).get(), | |||
); | |||
@@ -79,10 +79,10 @@ it('should be able to delete Portfolio', async () => { | |||
expect(byText('deletion.page').get()).toBeInTheDocument(); | |||
expect(byText('portfolio_deletion.page.description').get()).toBeInTheDocument(); | |||
user.click(byRole('button', { name: 'delete' }).get()); | |||
await user.click(byRole('button', { name: 'delete' }).get()); | |||
expect(await byRole('dialog', { name: 'qualifier.delete.VW' }).find()).toBeInTheDocument(); | |||
user.click( | |||
await user.click( | |||
byRole('dialog', { name: 'qualifier.delete.VW' }).byRole('button', { name: 'delete' }).get(), | |||
); | |||
@@ -107,9 +107,9 @@ it('should be able to delete Application', async () => { | |||
expect(byText('deletion.page').get()).toBeInTheDocument(); | |||
expect(byText('application_deletion.page.description').get()).toBeInTheDocument(); | |||
user.click(byRole('button', { name: 'delete' }).get()); | |||
await user.click(byRole('button', { name: 'delete' }).get()); | |||
expect(await byRole('dialog', { name: 'qualifier.delete.APP' }).find()).toBeInTheDocument(); | |||
user.click( | |||
await user.click( | |||
byRole('dialog', { name: 'qualifier.delete.APP' }).byRole('button', { name: 'delete' }).get(), | |||
); | |||
@@ -183,7 +183,9 @@ it('should filter projects', async () => { | |||
const user = userEvent.setup(); | |||
renderProjectManagementApp(); | |||
await waitFor(() => expect(ui.row.getAll()).toHaveLength(5)); | |||
await selectEvent.select(ui.visibilityFilter.get(), 'visibility.public'); | |||
await waitFor(() => { | |||
selectEvent.select(ui.visibilityFilter.get(), 'visibility.public'); | |||
}); | |||
await waitFor(() => expect(ui.row.getAll()).toHaveLength(4)); | |||
await user.click(ui.analysisDateFilter.get()); | |||
await user.click(await screen.findByRole('gridcell', { name: '5' })); | |||
@@ -191,11 +193,15 @@ it('should filter projects', async () => { | |||
await user.click(ui.provisionedFilter.get()); | |||
expect(ui.row.getAll()).toHaveLength(2); | |||
expect(ui.row.getAll()[1]).toHaveTextContent('Project 4'); | |||
await selectEvent.select(ui.qualifierFilter.get(), 'qualifiers.VW'); | |||
expect(ui.provisionedFilter.query()).not.toBeInTheDocument(); | |||
await waitFor(() => { | |||
selectEvent.select(ui.qualifierFilter.get(), 'qualifiers.VW'); | |||
}); | |||
await waitFor(() => expect(ui.provisionedFilter.query()).not.toBeInTheDocument()); | |||
expect(ui.row.getAll()).toHaveLength(2); | |||
await waitFor(() => expect(ui.row.getAll()[1]).toHaveTextContent('Portfolio 1')); | |||
await selectEvent.select(ui.qualifierFilter.get(), 'qualifiers.APP'); | |||
await waitFor(() => { | |||
selectEvent.select(ui.qualifierFilter.get(), 'qualifiers.APP'); | |||
}); | |||
expect(ui.provisionedFilter.query()).not.toBeInTheDocument(); | |||
expect(ui.row.getAll()).toHaveLength(2); | |||
await waitFor(() => expect(ui.row.getAll()[1]).toHaveTextContent('Application 1')); | |||
@@ -207,12 +213,16 @@ it('should search by text', async () => { | |||
await waitFor(() => expect(ui.row.getAll()).toHaveLength(5)); | |||
await user.type(ui.searchFilter.get(), 'provision'); | |||
expect(ui.row.getAll()).toHaveLength(2); | |||
await selectEvent.select(ui.qualifierFilter.get(), 'qualifiers.VW'); | |||
await waitFor(() => { | |||
selectEvent.select(ui.qualifierFilter.get(), 'qualifiers.VW'); | |||
}); | |||
await waitFor(() => expect(ui.row.getAll()).toHaveLength(4)); | |||
expect(ui.searchFilter.get()).toHaveValue(''); | |||
await user.type(ui.searchFilter.get(), 'Portfolio 2'); | |||
expect(ui.row.getAll()).toHaveLength(2); | |||
await selectEvent.select(ui.qualifierFilter.get(), 'qualifiers.APP'); | |||
await waitFor(() => { | |||
selectEvent.select(ui.qualifierFilter.get(), 'qualifiers.APP'); | |||
}); | |||
await waitFor(() => expect(ui.row.getAll()).toHaveLength(4)); | |||
expect(ui.searchFilter.get()).toHaveValue(''); | |||
await user.type(ui.searchFilter.get(), 'Application 3'); | |||
@@ -396,7 +406,9 @@ it('should load more and change the filter without caching old pages', async () | |||
expect(projectRows[1]).toHaveTextContent('Project 0'); | |||
expect(projectRows[60]).toHaveTextContent('Project 59'); | |||
await selectEvent.select(ui.qualifierFilter.get(), 'qualifiers.VW'); | |||
await waitFor(() => { | |||
selectEvent.select(ui.qualifierFilter.get(), 'qualifiers.VW'); | |||
}); | |||
await waitFor(() => expect(projectRows[1]).not.toBeInTheDocument()); | |||
const portfolioRows = ui.row.getAll(); | |||
expect(portfolioRows).toHaveLength(51); |
@@ -101,9 +101,11 @@ it('should behave correctly', async () => { | |||
// Incorrect login. | |||
await user.type(loginField, 'janedoe'); | |||
await user.type(passwordField, 'invalid'); | |||
// Don't use userEvent.click() here. This allows us to more easily see the loading state changes. | |||
submitButton.click(); | |||
await waitFor(() => expect(submitButton).toBeDisabled()); // Loading. | |||
await waitFor(() => { | |||
// Don't use userEvent.click() here. This allows us to more easily see the loading state changes. | |||
submitButton.click(); | |||
expect(submitButton).toBeDisabled(); // Loading | |||
}); | |||
await waitFor(() => { | |||
expect(addGlobalErrorMessage).toHaveBeenCalledWith('login.authentication_failed'); | |||
}); |
@@ -722,13 +722,17 @@ it('accessibility', async () => { | |||
// user creation dialog should be accessible | |||
await user.click(await ui.createUserButton.find()); | |||
expect(await ui.dialogCreateUser.find()).toBeInTheDocument(); | |||
await expect(ui.dialogCreateUser.get()).toHaveNoA11yViolations(); | |||
await waitFor(async () => { | |||
await expect(ui.dialogCreateUser.get()).toHaveNoA11yViolations(); | |||
}); | |||
await user.click(ui.cancelButton.get()); | |||
// users group membership dialog should be accessible | |||
user.click(await ui.aliceUpdateGroupButton.find()); | |||
await user.click(await ui.aliceUpdateGroupButton.find()); | |||
expect(await ui.dialogGroups.find()).toBeInTheDocument(); | |||
await expect(await ui.dialogGroups.find()).toHaveNoA11yViolations(); | |||
await waitFor(async () => { | |||
await expect(await ui.dialogGroups.find()).toHaveNoA11yViolations(); | |||
}); | |||
await user.click(ui.doneButton.get()); | |||
// user update dialog should be accessible | |||
@@ -748,7 +752,9 @@ it('accessibility', async () => { | |||
); | |||
expect(await ui.dialogTokens.find()).toBeInTheDocument(); | |||
await expect(await ui.dialogTokens.find()).toHaveNoA11yViolations(); | |||
await waitFor(async () => { | |||
await expect(await ui.dialogTokens.find()).toHaveNoA11yViolations(); | |||
}); | |||
await user.click(ui.closeButton.get()); | |||
// user password dialog should be accessible |