diff --git a/.eslintrc b/.eslintrc
index 9ad2a337f47..b34a9c242e0 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,7 +1,18 @@
{
"extends": ["@grafana/eslint-config", "plugin:react/jsx-runtime"],
"root": true,
- "plugins": ["@emotion", "lodash", "jest", "import", "jsx-a11y", "@grafana", "no-barrel-files"],
+ "plugins": [
+ "@emotion",
+ "lodash",
+ "jest",
+ "import",
+ "jsx-a11y",
+ "@grafana",
+ "no-barrel-files",
+ // Included so betterer doesn't fail when processing all files,
+ // as other parts of the code use testing-library plugin
+ "testing-library",
+ ],
"settings": {
"import/internal-regex": "^(app/)|(@grafana)",
"import/external-module-folders": ["node_modules", ".yarn"],
diff --git a/package.json b/package.json
index 19f20a27b4c..16aae3333e1 100644
--- a/package.json
+++ b/package.json
@@ -178,6 +178,7 @@
"eslint-plugin-no-barrel-files": "^1.1.0",
"eslint-plugin-react": "7.34.2",
"eslint-plugin-react-hooks": "4.6.0",
+ "eslint-plugin-testing-library": "^6.2.2",
"eslint-scope": "^8.0.0",
"eslint-webpack-plugin": "4.2.0",
"expose-loader": "5.0.0",
diff --git a/public/app/features/alerting/.eslintrc b/public/app/features/alerting/.eslintrc
new file mode 100644
index 00000000000..5d4da843de0
--- /dev/null
+++ b/public/app/features/alerting/.eslintrc
@@ -0,0 +1,9 @@
+{
+ "plugins": ["testing-library"],
+ "overrides": [
+ {
+ "files": ["**/__tests__/**/*.[jt]s?(x)", "**/?(*.)+(spec|test).[jt]s?(x)"],
+ "extends": ["plugin:testing-library/react"],
+ },
+ ],
+}
diff --git a/public/app/features/alerting/unified/CloneRuleEditor.test.tsx b/public/app/features/alerting/unified/CloneRuleEditor.test.tsx
index d8893fbdfe3..3e5d853cb72 100644
--- a/public/app/features/alerting/unified/CloneRuleEditor.test.tsx
+++ b/public/app/features/alerting/unified/CloneRuleEditor.test.tsx
@@ -104,20 +104,20 @@ describe('CloneRuleEditor', function () {
await waitFor(() => {
expect(ui.inputs.name.get()).toHaveValue(`${grafanaRulerRule.grafana_alert.title} (copy)`);
- expect(ui.inputs.folderContainer.get()).toHaveTextContent('folder-one');
- expect(ui.inputs.group.get()).toHaveTextContent(grafanaRulerRule.grafana_alert.rule_group);
- expect(
- byRole('listitem', {
- name: 'severity: critical',
- }).get()
- ).toBeInTheDocument();
- expect(
- byRole('listitem', {
- name: 'region: nasa',
- }).get()
- ).toBeInTheDocument();
- expect(ui.inputs.annotationValue(0).get()).toHaveTextContent(grafanaRulerRule.annotations[Annotation.summary]);
});
+ expect(ui.inputs.folderContainer.get()).toHaveTextContent('folder-one');
+ expect(ui.inputs.group.get()).toHaveTextContent(grafanaRulerRule.grafana_alert.rule_group);
+ expect(
+ byRole('listitem', {
+ name: 'severity: critical',
+ }).get()
+ ).toBeInTheDocument();
+ expect(
+ byRole('listitem', {
+ name: 'region: nasa',
+ }).get()
+ ).toBeInTheDocument();
+ expect(ui.inputs.annotationValue(0).get()).toHaveTextContent(grafanaRulerRule.annotations[Annotation.summary]);
});
});
@@ -174,21 +174,21 @@ describe('CloneRuleEditor', function () {
await waitFor(() => {
expect(ui.inputs.name.get()).toHaveValue('First Ruler Rule (copy)');
- expect(ui.inputs.expr.get()).toHaveValue('vector(1) > 0');
- expect(ui.inputs.namespace.get()).toHaveTextContent('namespace-one');
- expect(ui.inputs.group.get()).toHaveTextContent('group1');
- expect(
- byRole('listitem', {
- name: 'severity: critical',
- }).get()
- ).toBeInTheDocument();
- expect(
- byRole('listitem', {
- name: 'region: nasa',
- }).get()
- ).toBeInTheDocument();
- expect(ui.inputs.annotationValue(0).get()).toHaveTextContent('This is a very important alert rule');
});
+ expect(ui.inputs.expr.get()).toHaveValue('vector(1) > 0');
+ expect(ui.inputs.namespace.get()).toHaveTextContent('namespace-one');
+ expect(ui.inputs.group.get()).toHaveTextContent('group1');
+ expect(
+ byRole('listitem', {
+ name: 'severity: critical',
+ }).get()
+ ).toBeInTheDocument();
+ expect(
+ byRole('listitem', {
+ name: 'region: nasa',
+ }).get()
+ ).toBeInTheDocument();
+ expect(ui.inputs.annotationValue(0).get()).toHaveTextContent('This is a very important alert rule');
});
});
diff --git a/public/app/features/alerting/unified/GrafanaRuleQueryViewer.test.tsx b/public/app/features/alerting/unified/GrafanaRuleQueryViewer.test.tsx
index 0eee3f57c69..b057ab9186e 100644
--- a/public/app/features/alerting/unified/GrafanaRuleQueryViewer.test.tsx
+++ b/public/app/features/alerting/unified/GrafanaRuleQueryViewer.test.tsx
@@ -1,4 +1,4 @@
-import { render, waitFor } from '@testing-library/react';
+import { render, waitFor, screen } from '@testing-library/react';
import { TestProvider } from 'test/helpers/TestProvider';
import { DataSourceRef } from '@grafana/schema';
@@ -73,12 +73,11 @@ describe('GrafanaRuleQueryViewer', () => {
getExpression('C', { type: '' }),
getExpression('D', { type: '' }),
];
- const { getByTestId } = render(
- ,
- { wrapper: TestProvider }
- );
+ render(, {
+ wrapper: TestProvider,
+ });
- await waitFor(() => expect(getByTestId('queries-container')).toHaveStyle('flex-wrap: wrap'));
- expect(getByTestId('expressions-container')).toHaveStyle('flex-wrap: wrap');
+ await waitFor(() => expect(screen.getByTestId('queries-container')).toHaveStyle('flex-wrap: wrap'));
+ expect(screen.getByTestId('expressions-container')).toHaveStyle('flex-wrap: wrap');
});
});
diff --git a/public/app/features/alerting/unified/RuleEditorCloudOnlyAllowed.test.tsx b/public/app/features/alerting/unified/RuleEditorCloudOnlyAllowed.test.tsx
index 6db787d57ac..477324181e0 100644
--- a/public/app/features/alerting/unified/RuleEditorCloudOnlyAllowed.test.tsx
+++ b/public/app/features/alerting/unified/RuleEditorCloudOnlyAllowed.test.tsx
@@ -183,7 +183,7 @@ describe('RuleEditor cloud: checking editable data sources', () => {
// render rule editor, select mimir/loki managed alerts
renderRuleEditor();
- await waitForElementToBeRemoved(screen.getAllByTestId('Spinner'));
+ await waitForElementToBeRemoved(screen.queryAllByTestId('Spinner'));
await ui.inputs.name.find();
diff --git a/public/app/features/alerting/unified/RuleEditorCloudRules.test.tsx b/public/app/features/alerting/unified/RuleEditorCloudRules.test.tsx
index d6af58c6bb3..224fa93a8ec 100644
--- a/public/app/features/alerting/unified/RuleEditorCloudRules.test.tsx
+++ b/public/app/features/alerting/unified/RuleEditorCloudRules.test.tsx
@@ -113,13 +113,13 @@ describe('RuleEditor cloud', () => {
const user = userEvent.setup();
renderRuleEditor();
- await waitForElementToBeRemoved(screen.getAllByTestId('Spinner'));
+ await waitForElementToBeRemoved(screen.queryAllByTestId('Spinner'));
const removeExpressionsButtons = screen.getAllByLabelText('Remove expression');
expect(removeExpressionsButtons).toHaveLength(2);
// Needs to wait for featrue discovery API call to finish - Check if ruler enabled
- await waitFor(() => expect(screen.getByText('Data source-managed')).toBeInTheDocument());
+ expect(await screen.findByText('Data source-managed')).toBeInTheDocument();
const switchToCloudButton = screen.getByText('Data source-managed');
expect(switchToCloudButton).toBeInTheDocument();
diff --git a/public/app/features/alerting/unified/RuleEditorGrafanaRules.test.tsx b/public/app/features/alerting/unified/RuleEditorGrafanaRules.test.tsx
index 3728c5e88c5..ebd179642d5 100644
--- a/public/app/features/alerting/unified/RuleEditorGrafanaRules.test.tsx
+++ b/public/app/features/alerting/unified/RuleEditorGrafanaRules.test.tsx
@@ -113,7 +113,7 @@ describe('RuleEditor grafana managed rules', () => {
] as DashboardSearchHit[]);
renderRuleEditor();
- await waitForElementToBeRemoved(screen.getAllByTestId('Spinner'));
+ await waitForElementToBeRemoved(screen.queryAllByTestId('Spinner'));
await userEvent.type(await ui.inputs.name.find(), 'my great new rule');
diff --git a/public/app/features/alerting/unified/RuleEditorRecordingRule.test.tsx b/public/app/features/alerting/unified/RuleEditorRecordingRule.test.tsx
index 5e02450bf44..523f4dcf3d4 100644
--- a/public/app/features/alerting/unified/RuleEditorRecordingRule.test.tsx
+++ b/public/app/features/alerting/unified/RuleEditorRecordingRule.test.tsx
@@ -147,7 +147,7 @@ describe('RuleEditor recording rules', () => {
});
renderRuleEditor(undefined, true);
- await waitForElementToBeRemoved(screen.getAllByTestId('Spinner'));
+ await waitForElementToBeRemoved(screen.queryAllByTestId('Spinner'));
await userEvent.type(await ui.inputs.name.find(), 'my great new recording rule');
const dataSourceSelect = ui.inputs.dataSource.get();
diff --git a/public/app/features/alerting/unified/RuleList.test.tsx b/public/app/features/alerting/unified/RuleList.test.tsx
index fdb5bd8280e..6d9673b1c7a 100644
--- a/public/app/features/alerting/unified/RuleList.test.tsx
+++ b/public/app/features/alerting/unified/RuleList.test.tsx
@@ -2,7 +2,7 @@ import { SerializedError } from '@reduxjs/toolkit';
import userEvent from '@testing-library/user-event';
import { SetupServer } from 'msw/node';
import { TestProvider } from 'test/helpers/TestProvider';
-import { prettyDOM, render, screen, waitFor, within } from 'test/test-utils';
+import { render, screen, waitFor, within } from 'test/test-utils';
import { byRole, byTestId, byText } from 'testing-library-selector';
import { PluginExtensionTypes } from '@grafana/data';
@@ -728,7 +728,6 @@ describe('RuleList', () => {
await userEvent.click(ui.editCloudGroupIcon.get(groups[0]));
await waitFor(() => expect(ui.editGroupModal.dialog.get()).toBeInTheDocument());
- prettyDOM(ui.editGroupModal.dialog.get());
expect(ui.editGroupModal.namespaceInput.get()).toHaveDisplayValue('namespace1');
expect(ui.editGroupModal.ruleGroupInput.get()).toHaveDisplayValue('group1');
diff --git a/public/app/features/alerting/unified/Settings.test.tsx b/public/app/features/alerting/unified/Settings.test.tsx
index 892c5a35969..2537fb1e800 100644
--- a/public/app/features/alerting/unified/Settings.test.tsx
+++ b/public/app/features/alerting/unified/Settings.test.tsx
@@ -49,10 +49,8 @@ describe('Alerting settings', () => {
it('should render the page with Built-in only enabled, others disabled', async () => {
render();
- await waitFor(() => {
- expect(ui.builtInAlertmanagerSection.get()).toBeInTheDocument();
- expect(ui.otherAlertmanagerSection.get()).toBeInTheDocument();
- });
+ expect(await ui.builtInAlertmanagerSection.find()).toBeInTheDocument();
+ expect(ui.otherAlertmanagerSection.get()).toBeInTheDocument();
// check internal alertmanager configuration
expect(ui.builtInAlertmanagerCard.get()).toBeInTheDocument();
diff --git a/public/app/features/alerting/unified/components/contact-points/ContactPoints.test.tsx b/public/app/features/alerting/unified/components/contact-points/ContactPoints.test.tsx
index 1f3dc40a3ad..ecef0d1e31d 100644
--- a/public/app/features/alerting/unified/components/contact-points/ContactPoints.test.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/ContactPoints.test.tsx
@@ -90,11 +90,8 @@ describe('contact points', () => {
it('should show / hide loading states, have all actions enabled', async () => {
renderWithProvider();
- await waitFor(async () => {
- expect(screen.getByText('Loading...')).toBeInTheDocument();
- await waitForElementToBeRemoved(screen.getByText('Loading...'));
- expect(screen.queryByTestId(selectors.components.Alert.alertV2('error'))).not.toBeInTheDocument();
- });
+ await waitForElementToBeRemoved(screen.queryByText('Loading...'));
+ expect(screen.queryByTestId(selectors.components.Alert.alertV2('error'))).not.toBeInTheDocument();
expect(screen.getByText('grafana-default-email')).toBeInTheDocument();
expect(screen.getAllByTestId('contact-point')).toHaveLength(5);
@@ -130,9 +127,7 @@ describe('contact points', () => {
renderWithProvider();
// wait for loading to be done
- await waitFor(async () => {
- expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
- });
+ await waitForElementToBeRemoved(screen.queryByText('Loading...'));
// should disable create contact point
expect(screen.getByRole('link', { name: 'add contact point' })).toHaveAttribute('aria-disabled', 'true');
@@ -252,8 +247,8 @@ describe('contact points', () => {
await userEvent.type(searchInput, 'slack');
expect(searchInput).toHaveValue('slack');
+ expect(await screen.findByText('Slack with multiple channels')).toBeInTheDocument();
await waitFor(() => {
- expect(screen.getByText('Slack with multiple channels')).toBeInTheDocument();
expect(screen.getAllByTestId('contact-point')).toHaveLength(1);
});
@@ -286,11 +281,8 @@ describe('contact points', () => {
it('should show / hide loading states, have the right actions enabled', async () => {
renderWithProvider(, undefined, { alertmanagerSourceName: MIMIR_DATASOURCE_UID });
- await waitFor(async () => {
- expect(screen.getByText('Loading...')).toBeInTheDocument();
- await waitForElementToBeRemoved(screen.getByText('Loading...'));
- expect(screen.queryByTestId(selectors.components.Alert.alertV2('error'))).not.toBeInTheDocument();
- });
+ await waitForElementToBeRemoved(screen.queryByText('Loading...'));
+ expect(screen.queryByTestId(selectors.components.Alert.alertV2('error'))).not.toBeInTheDocument();
expect(screen.getByText('mixed')).toBeInTheDocument();
expect(screen.getByText('some webhook')).toBeInTheDocument();
@@ -344,11 +336,8 @@ describe('contact points', () => {
alertmanagerSourceName: VANILLA_ALERTMANAGER_DATASOURCE_UID,
});
- await waitFor(async () => {
- expect(screen.getByText('Loading...')).toBeInTheDocument();
- await waitForElementToBeRemoved(screen.getByText('Loading...'));
- expect(screen.queryByTestId(selectors.components.Alert.alertV2('error'))).not.toBeInTheDocument();
- });
+ await waitForElementToBeRemoved(screen.queryByText('Loading...'));
+ expect(screen.queryByTestId(selectors.components.Alert.alertV2('error'))).not.toBeInTheDocument();
expect(screen.queryByRole('link', { name: 'add contact point' })).not.toBeInTheDocument();
diff --git a/public/app/features/alerting/unified/components/mute-timings/MuteTimingsTable.test.tsx b/public/app/features/alerting/unified/components/mute-timings/MuteTimingsTable.test.tsx
index 6ceffac48e0..f14519d217d 100644
--- a/public/app/features/alerting/unified/components/mute-timings/MuteTimingsTable.test.tsx
+++ b/public/app/features/alerting/unified/components/mute-timings/MuteTimingsTable.test.tsx
@@ -1,4 +1,4 @@
-import { render, waitFor } from '@testing-library/react';
+import { render, waitFor, screen } from '@testing-library/react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
@@ -36,15 +36,15 @@ describe('MuteTimingsTable', () => {
AccessControlAction.AlertingNotificationsRead,
AccessControlAction.AlertingNotificationsWrite,
]);
- const { findByRole } = renderWithProvider();
- expect(await findByRole('button', { name: /export all/i })).toBeInTheDocument();
+ renderWithProvider();
+ expect(await screen.findByRole('button', { name: /export all/i })).toBeInTheDocument();
});
it('It does not show export button when not allowed ', async () => {
// when not allowed
grantUserPermissions([]);
- const { queryByRole } = renderWithProvider();
+ renderWithProvider();
await waitFor(() => {
- expect(queryByRole('button', { name: /export all/i })).not.toBeInTheDocument();
+ expect(screen.queryByRole('button', { name: /export all/i })).not.toBeInTheDocument();
});
});
it('It does not show export button when not supported ', async () => {
@@ -53,9 +53,9 @@ describe('MuteTimingsTable', () => {
AccessControlAction.AlertingNotificationsRead,
AccessControlAction.AlertingNotificationsWrite,
]);
- const { queryByRole } = renderWithProvider('potato');
+ renderWithProvider('potato');
await waitFor(() => {
- expect(queryByRole('button', { name: /export all/i })).not.toBeInTheDocument();
+ expect(screen.queryByRole('button', { name: /export all/i })).not.toBeInTheDocument();
});
});
});
diff --git a/public/app/features/alerting/unified/components/receivers/TemplatePreview.test.tsx b/public/app/features/alerting/unified/components/receivers/TemplatePreview.test.tsx
index a4c936dbbc5..7abcf79a6e6 100644
--- a/public/app/features/alerting/unified/components/receivers/TemplatePreview.test.tsx
+++ b/public/app/features/alerting/unified/components/receivers/TemplatePreview.test.tsx
@@ -129,12 +129,12 @@ describe('TemplatePreview component', () => {
{ wrapper: getProviderWraper() }
);
+ const previews = ui.resultItems.getAll;
await waitFor(() => {
- const previews = ui.resultItems.getAll();
- expect(previews).toHaveLength(2);
- expect(previews[0]).toHaveTextContent('This is the template result bla bla bla');
- expect(previews[1]).toHaveTextContent('This is the template2 result bla bla bla');
+ expect(previews()).toHaveLength(2);
});
+ expect(previews()[0]).toHaveTextContent('This is the template result bla bla bla');
+ expect(previews()[1]).toHaveTextContent('This is the template2 result bla bla bla');
});
it('Should render preview response with some errors, if payload has correct format ', async () => {
@@ -157,15 +157,14 @@ describe('TemplatePreview component', () => {
{ wrapper: getProviderWraper() }
);
+ const alerts = () => screen.getAllByTestId(Components.Alert.alertV2('error'));
await waitFor(() => {
- const alerts = screen.getAllByTestId(Components.Alert.alertV2('error'));
- const previewContent = screen.getByRole('listitem');
-
- expect(alerts).toHaveLength(2);
- expect(alerts[0]).toHaveTextContent(/Unexpected "{" in operand/i);
- expect(alerts[1]).toHaveTextContent(/Unexpected "{" in operand/i);
-
- expect(previewContent).toHaveTextContent('This is the template result bla bla bla');
+ expect(alerts()).toHaveLength(2);
});
+ expect(alerts()[0]).toHaveTextContent(/Unexpected "{" in operand/i);
+ expect(alerts()[1]).toHaveTextContent(/Unexpected "{" in operand/i);
+
+ const previewContent = screen.getByRole('listitem');
+ expect(previewContent).toHaveTextContent('This is the template result bla bla bla');
});
});
diff --git a/public/app/features/alerting/unified/components/receivers/form/GrafanaReceiverForm.test.tsx b/public/app/features/alerting/unified/components/receivers/form/GrafanaReceiverForm.test.tsx
index 105e6553fc5..f4832592872 100644
--- a/public/app/features/alerting/unified/components/receivers/form/GrafanaReceiverForm.test.tsx
+++ b/public/app/features/alerting/unified/components/receivers/form/GrafanaReceiverForm.test.tsx
@@ -51,9 +51,11 @@ describe('GrafanaReceiverForm', () => {
await clickSelectOption(byTestId('items.0.type').get(), 'Grafana OnCall');
// Clicking on a disable element shouldn't change the form value. email is the default value
+ // eslint-disable-next-line testing-library/no-node-access
expect(ui.integrationType.get().closest('form')).toHaveFormValues({ 'items.0.type': 'email' });
await clickSelectOption(byTestId('items.0.type').get(), 'Alertmanager');
+ // eslint-disable-next-line testing-library/no-node-access
expect(ui.integrationType.get().closest('form')).toHaveFormValues({ 'items.0.type': 'prometheus-alertmanager' });
});
@@ -73,6 +75,7 @@ describe('GrafanaReceiverForm', () => {
await clickSelectOption(byTestId('items.0.type').get(), 'Grafana OnCall');
+ // eslint-disable-next-line testing-library/no-node-access
expect(ui.integrationType.get().closest('form')).toHaveFormValues({ 'items.0.type': 'oncall' });
expect(ui.onCallIntegrationType.get()).toBeInTheDocument();
@@ -87,6 +90,7 @@ describe('GrafanaReceiverForm', () => {
await user.type(ui.newOnCallIntegrationName.get(), 'emea-oncall');
+ // eslint-disable-next-line testing-library/no-node-access
expect(ui.integrationType.get().closest('form')).toHaveFormValues({
'items.0.settings.integration_type': 'new_oncall_integration',
'items.0.settings.integration_name': 'emea-oncall',
@@ -98,6 +102,7 @@ describe('GrafanaReceiverForm', () => {
await clickSelectOption(ui.existingOnCallIntegrationSelect(0).get(), 'apac-oncall');
+ // eslint-disable-next-line testing-library/no-node-access
expect(ui.integrationType.get().closest('form')).toHaveFormValues({
'items.0.settings.url': 'https://apac.oncall.example.com',
'items.0.settings.integration_name': undefined,
diff --git a/public/app/features/alerting/unified/components/rule-editor/AnnotationsStep.test.tsx b/public/app/features/alerting/unified/components/rule-editor/AnnotationsStep.test.tsx
index ca31bc42c17..565f7ed6cf6 100644
--- a/public/app/features/alerting/unified/components/rule-editor/AnnotationsStep.test.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/AnnotationsStep.test.tsx
@@ -1,6 +1,6 @@
import userEvent from '@testing-library/user-event';
import { FormProvider, useForm } from 'react-hook-form';
-import { findByRole, findByText, findByTitle, getByTestId, queryByText, render } from 'test/test-utils';
+import { screen, render, within } from 'test/test-utils';
import { byRole, byTestId } from 'testing-library-selector';
import 'core-js/stable/structured-clone';
@@ -97,10 +97,10 @@ describe('AnnotationsField', function () {
await user.click(ui.setDashboardButton.get());
expect(ui.dashboardPicker.confirmButton.get()).toBeDisabled();
- await user.click(await findByTitle(ui.dashboardPicker.dialog.get(), 'My dashboard'));
+ await user.click(await screen.findByTitle('My dashboard'));
expect(ui.dashboardPicker.confirmButton.get()).toBeDisabled();
- await user.click(await findByText(ui.dashboardPicker.dialog.get(), 'First panel'));
+ await user.click(await screen.findByText('First panel'));
expect(ui.dashboardPicker.confirmButton.get()).toBeEnabled();
});
@@ -125,9 +125,9 @@ describe('AnnotationsField', function () {
render();
await user.click(ui.setDashboardButton.get());
- await user.click(await findByTitle(ui.dashboardPicker.dialog.get(), 'My dashboard'));
+ await user.click(await screen.findByTitle('My dashboard'));
- await user.click(await findByText(ui.dashboardPicker.dialog.get(), 'Second panel'));
+ await user.click(await screen.findByText('Second panel'));
await user.click(ui.dashboardPicker.confirmButton.get());
@@ -163,10 +163,10 @@ describe('AnnotationsField', function () {
await user.click(ui.setDashboardButton.get());
expect(ui.dashboardPicker.confirmButton.get()).toBeDisabled();
- await user.click(await findByTitle(ui.dashboardPicker.dialog.get(), 'My dashboard'));
+ await user.click(await screen.findByTitle('My dashboard'));
- expect(await findByText(ui.dashboardPicker.dialog.get(), 'First panel')).toBeInTheDocument();
- expect(await queryByText(ui.dashboardPicker.dialog.get(), 'Row panel')).not.toBeInTheDocument();
+ expect(await screen.findByText('First panel')).toBeInTheDocument();
+ expect(screen.queryByText('Row panel')).not.toBeInTheDocument();
});
it('should show panels within collapsed rows', async function () {
@@ -198,11 +198,11 @@ describe('AnnotationsField', function () {
await user.click(ui.setDashboardButton.get());
expect(ui.dashboardPicker.confirmButton.get()).toBeDisabled();
- await user.click(await findByTitle(ui.dashboardPicker.dialog.get(), 'My dashboard'));
+ await user.click(await screen.findByTitle('My dashboard'));
- expect(await findByText(ui.dashboardPicker.dialog.get(), 'First panel')).toBeInTheDocument();
- expect(await queryByText(ui.dashboardPicker.dialog.get(), 'Row panel')).not.toBeInTheDocument();
- expect(await findByText(ui.dashboardPicker.dialog.get(), 'Panel within collapsed row')).toBeInTheDocument();
+ expect(await screen.findByText('First panel')).toBeInTheDocument();
+ expect(screen.queryByText('Row panel')).not.toBeInTheDocument();
+ expect(await screen.findByText('Panel within collapsed row')).toBeInTheDocument();
});
// this test _should_ work in theory but something is stopping the 'onClick' function on the dashboard item
@@ -252,11 +252,11 @@ describe('AnnotationsField', function () {
expect(annotationValueElements[0]).toHaveTextContent('dash-test-uid');
expect(annotationValueElements[1]).toHaveTextContent('1');
- const { confirmButton, dialog } = ui.dashboardPicker;
+ const { confirmButton } = ui.dashboardPicker;
await user.click(ui.setDashboardButton.get());
- await user.click(await findByRole(dialog.get(), 'button', { name: /My other dashboard/ }));
- await user.click(await findByRole(dialog.get(), 'button', { name: /Third panel/ }));
+ await user.click(await screen.findByRole('button', { name: /My other dashboard/ }));
+ await user.click(await screen.findByRole('button', { name: /Third panel/ }));
await user.click(confirmButton.get());
expect(ui.dashboardPicker.dialog.query()).not.toBeInTheDocument();
@@ -296,14 +296,12 @@ describe('AnnotationsField', function () {
render();
- const { dialog } = ui.dashboardPicker;
-
await user.click(ui.setDashboardButton.get());
- await user.click(await findByTitle(dialog.get(), 'My dashboard'));
+ await user.click(await screen.findByTitle('My dashboard'));
- const warnedPanel = await findByRole(dialog.get(), 'button', { name: /First panel/ });
+ const warnedPanel = await screen.findByRole('button', { name: /First panel/ });
- expect(getByTestId(warnedPanel, 'warning-icon')).toBeInTheDocument();
+ expect(within(warnedPanel).getByTestId('warning-icon')).toBeInTheDocument();
});
it('should render when panels do not contain certain fields', async () => {
diff --git a/public/app/features/alerting/unified/components/rule-editor/DashboardPicker.test.tsx b/public/app/features/alerting/unified/components/rule-editor/DashboardPicker.test.tsx
index 5d49288dbb7..b310095991b 100644
--- a/public/app/features/alerting/unified/components/rule-editor/DashboardPicker.test.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/DashboardPicker.test.tsx
@@ -1,4 +1,4 @@
-import { render, waitFor } from '@testing-library/react';
+import { render } from '@testing-library/react';
import { noop } from 'lodash';
import { Props } from 'react-virtualized-auto-sizer';
import { byRole } from 'testing-library-selector';
@@ -63,17 +63,15 @@ describe('DashboardPicker', () => {
wrapper: TestProvider,
});
- await waitFor(() => {
- expect(ui.dashboardButton(/Dashboard 1/).get()).toBeInTheDocument();
- expect(ui.dashboardButton(/Dashboard 2/).get()).toBeInTheDocument();
- expect(ui.dashboardButton(/Dashboard 3/).get()).toBeInTheDocument();
+ expect(await ui.dashboardButton(/Dashboard 1/).find()).toBeInTheDocument();
+ expect(ui.dashboardButton(/Dashboard 2/).get()).toBeInTheDocument();
+ expect(ui.dashboardButton(/Dashboard 3/).get()).toBeInTheDocument();
- const panels = ui.dashboardButton(//).getAll();
- expect(panels).toHaveLength(3);
+ const panels = ui.dashboardButton(//).getAll();
+ expect(panels).toHaveLength(3);
- panels.forEach((panel) => {
- expect(panel).not.toBeDisabled();
- });
+ panels.forEach((panel) => {
+ expect(panel).not.toBeDisabled();
});
});
});
diff --git a/public/app/features/alerting/unified/components/rule-editor/EvaluationGroupQuickPick.test.tsx b/public/app/features/alerting/unified/components/rule-editor/EvaluationGroupQuickPick.test.tsx
index d1a927fbbdf..3effadef96f 100644
--- a/public/app/features/alerting/unified/components/rule-editor/EvaluationGroupQuickPick.test.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/EvaluationGroupQuickPick.test.tsx
@@ -1,6 +1,4 @@
-import { screen } from '@testing-library/dom';
-import { render } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
+import { render, screen, userEvent } from 'test/test-utils';
import { getEvaluationGroupOptions, EvaluationGroupQuickPick } from './EvaluationGroupQuickPick';
diff --git a/public/app/features/alerting/unified/components/rule-editor/PendingPeriodQuickPick.test.tsx b/public/app/features/alerting/unified/components/rule-editor/PendingPeriodQuickPick.test.tsx
index d77c2f74426..fa7bbac5699 100644
--- a/public/app/features/alerting/unified/components/rule-editor/PendingPeriodQuickPick.test.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/PendingPeriodQuickPick.test.tsx
@@ -1,6 +1,4 @@
-import { screen } from '@testing-library/dom';
-import { render } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
+import { render, screen, userEvent } from 'test/test-utils';
import { PendingPeriodQuickPick } from './PendingPeriodQuickPick';
diff --git a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/SimplifiedRuleEditor.test.tsx b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/SimplifiedRuleEditor.test.tsx
index be567a58d46..dbc3cea4714 100644
--- a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/SimplifiedRuleEditor.test.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/SimplifiedRuleEditor.test.tsx
@@ -93,6 +93,7 @@ describe('Can create a new grafana managed alert unsing simplified routing', ()
const user = userEvent.setup();
renderSimplifiedRuleEditor();
+ await waitForElementToBeRemoved(screen.queryAllByTestId('Spinner'));
await user.type(await ui.inputs.name.find(), 'my great new rule');
@@ -111,7 +112,7 @@ describe('Can create a new grafana managed alert unsing simplified routing', ()
it('simplified routing is not available when Grafana AM is not enabled', async () => {
setAlertmanagerChoices(AlertmanagerChoice.External, 1);
renderSimplifiedRuleEditor();
- await waitForElementToBeRemoved(screen.getAllByTestId('Spinner'));
+ await waitForElementToBeRemoved(screen.queryAllByTestId('Spinner'));
expect(ui.inputs.simplifiedRouting.contactPointRouting.query()).not.toBeInTheDocument();
});
@@ -121,6 +122,7 @@ describe('Can create a new grafana managed alert unsing simplified routing', ()
const contactPointName = 'lotsa-emails';
renderSimplifiedRuleEditor();
+ await waitForElementToBeRemoved(screen.queryAllByTestId('Spinner'));
await user.type(await ui.inputs.name.find(), 'my great new rule');
diff --git a/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPreview.test.tsx b/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPreview.test.tsx
index 17cb3f64394..e0fc849dcd8 100644
--- a/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPreview.test.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPreview.test.tsx
@@ -147,14 +147,14 @@ describe('NotificationPreview', () => {
// we expect the alert manager label to be missing as there is only one alert manager configured to receive alerts
await waitFor(() => {
expect(ui.grafanaAlertManagerLabel.query()).not.toBeInTheDocument();
- expect(ui.otherAlertManagerLabel.query()).not.toBeInTheDocument();
});
+ expect(ui.otherAlertManagerLabel.query()).not.toBeInTheDocument();
+ const matchingPoliciesElements = ui.route.queryAll;
await waitFor(() => {
- const matchingPoliciesElements = ui.route.queryAll();
- expect(matchingPoliciesElements).toHaveLength(1);
- expect(matchingPoliciesElements[0]).toHaveTextContent(/tomato = red/);
+ expect(matchingPoliciesElements()).toHaveLength(1);
});
+ expect(matchingPoliciesElements()[0]).toHaveTextContent(/tomato = red/);
});
it('should render notification preview with alert manager sections, when having more than one alert manager configured to receive alerts', async () => {
// two alert managers configured to receive alerts
@@ -174,8 +174,8 @@ describe('NotificationPreview', () => {
// we expect the alert manager label to be present as there is more than one alert manager configured to receive alerts
await waitFor(() => {
expect(ui.grafanaAlertManagerLabel.query()).toBeInTheDocument();
- expect(ui.otherAlertManagerLabel.query()).toBeInTheDocument();
});
+ expect(ui.otherAlertManagerLabel.query()).toBeInTheDocument();
const matchingPoliciesElements = ui.route.queryAll();
expect(matchingPoliciesElements).toHaveLength(2);
diff --git a/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.test.tsx b/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.test.tsx
index 40a0aa4a1fe..ed59a8e9791 100644
--- a/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.test.tsx
+++ b/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.test.tsx
@@ -170,10 +170,8 @@ describe('RuleViewer', () => {
}
// actions
- await waitFor(() => {
- expect(ELEMENTS.actions.edit.get()).toBeInTheDocument();
- expect(ELEMENTS.actions.more.button.get()).toBeInTheDocument();
- });
+ expect(await ELEMENTS.actions.edit.find()).toBeInTheDocument();
+ expect(ELEMENTS.actions.more.button.get()).toBeInTheDocument();
// check the "more actions" button
await userEvent.click(ELEMENTS.actions.more.button.get());
diff --git a/public/app/features/alerting/unified/components/rules/state-history/LogRecordViewer.test.tsx b/public/app/features/alerting/unified/components/rules/state-history/LogRecordViewer.test.tsx
index 6ff72a88fb8..3ad55149827 100644
--- a/public/app/features/alerting/unified/components/rules/state-history/LogRecordViewer.test.tsx
+++ b/public/app/features/alerting/unified/components/rules/state-history/LogRecordViewer.test.tsx
@@ -1,4 +1,4 @@
-import { getByTestId, render } from '@testing-library/react';
+import { screen, render } from '@testing-library/react';
import { byRole } from 'testing-library-selector';
import { LogRecordViewerByTimestamp } from './LogRecordViewer';
@@ -22,8 +22,8 @@ describe('LogRecordViewerByTimestamp', () => {
const logElement = ui.log.get();
expect(logElement).toBeInTheDocument();
- const entry1 = getByTestId(logElement, 1681739580000);
- const entry2 = getByTestId(logElement, 1681739600000);
+ const entry1 = screen.getByTestId(1681739580000);
+ const entry2 = screen.getByTestId(1681739600000);
expect(entry1).toHaveTextContent('foo=bar');
expect(entry1).toHaveTextContent('severity=warning');
diff --git a/public/app/features/alerting/unified/hooks/useAbilities.test.tsx b/public/app/features/alerting/unified/hooks/useAbilities.test.tsx
index ddea4463b14..9b24cabbffe 100644
--- a/public/app/features/alerting/unified/hooks/useAbilities.test.tsx
+++ b/public/app/features/alerting/unified/hooks/useAbilities.test.tsx
@@ -39,10 +39,10 @@ describe('alertmanager abilities', () => {
})
);
- const abilities = renderHook(() => useAllAlertmanagerAbilities(), {
+ const { result } = renderHook(() => useAllAlertmanagerAbilities(), {
wrapper: createAlertmanagerWrapper('does-not-exist'),
});
- expect(abilities.result.current).toMatchSnapshot();
+ expect(result.current).toMatchSnapshot();
});
it('should report everything is supported for builtin alertmanager', () => {
@@ -55,36 +55,36 @@ describe('alertmanager abilities', () => {
grantUserPermissions([AccessControlAction.AlertingNotificationsRead, AccessControlAction.AlertingInstanceRead]);
- const abilities = renderHook(() => useAllAlertmanagerAbilities(), {
+ const { result } = renderHook(() => useAllAlertmanagerAbilities(), {
wrapper: createAlertmanagerWrapper(GRAFANA_RULES_SOURCE_NAME),
});
- Object.values(abilities.result.current).forEach(([supported]) => {
+ Object.values(result.current).forEach(([supported]) => {
expect(supported).toBe(true);
});
// since we only granted "read" permissions, only those should be allowed
- const viewAbility = renderHook(() => useAlertmanagerAbility(AlertmanagerAction.ViewSilence), {
+ const { result: viewResult } = renderHook(() => useAlertmanagerAbility(AlertmanagerAction.ViewSilence), {
wrapper: createAlertmanagerWrapper(GRAFANA_RULES_SOURCE_NAME),
});
- const [viewSupported, viewAllowed] = viewAbility.result.current;
+ const [viewSupported, viewAllowed] = viewResult.current;
expect(viewSupported).toBe(true);
expect(viewAllowed).toBe(true);
// editing should not be allowed, but supported
- const editAbility = renderHook(() => useAlertmanagerAbility(AlertmanagerAction.ViewSilence), {
+ const { result: editResult } = renderHook(() => useAlertmanagerAbility(AlertmanagerAction.ViewSilence), {
wrapper: createAlertmanagerWrapper(GRAFANA_RULES_SOURCE_NAME),
});
- const [editSupported, editAllowed] = editAbility.result.current;
+ const [editSupported, editAllowed] = editResult.current;
expect(editSupported).toBe(true);
expect(editAllowed).toBe(true);
// record the snapshot to prevent future regressions
- expect(abilities.result.current).toMatchSnapshot();
+ expect(result.current).toMatchSnapshot();
});
it('should report everything except exporting for Mimir alertmanager', () => {
@@ -105,11 +105,11 @@ describe('alertmanager abilities', () => {
AccessControlAction.AlertingInstancesExternalWrite,
]);
- const abilities = renderHook(() => useAllAlertmanagerAbilities(), {
+ const { result } = renderHook(() => useAllAlertmanagerAbilities(), {
wrapper: createAlertmanagerWrapper('mimir'),
});
- expect(abilities.result.current).toMatchSnapshot();
+ expect(result.current).toMatchSnapshot();
});
it('should be able to return multiple abilities', () => {
@@ -122,7 +122,7 @@ describe('alertmanager abilities', () => {
grantUserPermissions([AccessControlAction.AlertingNotificationsRead]);
- const abilities = renderHook(
+ const { result } = renderHook(
() =>
useAlertmanagerAbilities([
AlertmanagerAction.ViewContactPoint,
@@ -134,10 +134,10 @@ describe('alertmanager abilities', () => {
}
);
- expect(abilities.result.current).toHaveLength(3);
- expect(abilities.result.current[0]).toStrictEqual([true, true]);
- expect(abilities.result.current[1]).toStrictEqual([true, false]);
- expect(abilities.result.current[2]).toStrictEqual([true, true]);
+ expect(result.current).toHaveLength(3);
+ expect(result.current[0]).toStrictEqual([true, true]);
+ expect(result.current[1]).toStrictEqual([true, false]);
+ expect(result.current[2]).toStrictEqual([true, true]);
});
});
@@ -163,17 +163,17 @@ describe('AlertRule abilities', () => {
it('should report that all actions are supported for a Grafana Managed alert rule', async () => {
const rule = getGrafanaRule();
- const abilities = renderHook(() => useAllAlertRuleAbilities(rule), { wrapper: TestProvider });
+ const { result } = renderHook(() => useAllAlertRuleAbilities(rule), { wrapper: TestProvider });
await waitFor(() => {
- const results = Object.values(abilities.result.current);
+ const results = Object.values(result.current);
for (const [supported, _allowed] of results) {
expect(supported).toBe(true);
}
});
- expect(abilities.result.current).toMatchSnapshot();
+ expect(result.current).toMatchSnapshot();
});
it('grants correct silence permissions for folder with silence create permission', async () => {
@@ -201,13 +201,13 @@ describe('AlertRule abilities', () => {
it('should report no permissions while we are loading data for cloud rule', async () => {
const rule = getCloudRule();
- const abilities = renderHook(() => useAllAlertRuleAbilities(rule), { wrapper: TestProvider });
+ const { result } = renderHook(() => useAllAlertRuleAbilities(rule), { wrapper: TestProvider });
await waitFor(() => {
- expect(abilities.result.current).not.toBeUndefined();
+ expect(result.current).not.toBeUndefined();
});
- expect(abilities.result.current).toMatchSnapshot();
+ expect(result.current).toMatchSnapshot();
});
it('should not allow certain actions for provisioned rules', () => {});
diff --git a/public/app/features/alerting/unified/hooks/useExternalAMSelector.test.tsx b/public/app/features/alerting/unified/hooks/useExternalAMSelector.test.tsx
index f41b489fb3b..a8f2c3224ff 100644
--- a/public/app/features/alerting/unified/hooks/useExternalAMSelector.test.tsx
+++ b/public/app/features/alerting/unified/hooks/useExternalAMSelector.test.tsx
@@ -23,12 +23,10 @@ describe('useExternalDataSourceAlertmanagers', () => {
const { result } = renderHook(() => useExternalDataSourceAlertmanagers(), { wrapper: TestProvider });
await waitFor(() => {
// Assert
- const { current } = result;
-
- expect(current).toHaveLength(1);
- expect(current[0].dataSourceSettings.uid).toBe('1');
- expect(current[0].dataSourceSettings.url).toBe('http://grafana.com');
+ expect(result.current).toHaveLength(1);
});
+ expect(result.current[0].dataSourceSettings.uid).toBe('1');
+ expect(result.current[0].dataSourceSettings.url).toBe('http://grafana.com');
});
it('Should have uninterested state if data source does not want alerts', async () => {
@@ -40,11 +38,9 @@ describe('useExternalDataSourceAlertmanagers', () => {
const { result } = renderHook(() => useExternalDataSourceAlertmanagers(), { wrapper: TestProvider });
await waitFor(() => {
// Assert
- const { current } = result;
-
- expect(current).toHaveLength(1);
- expect(current[0].status).toBe('uninterested');
+ expect(result.current).toHaveLength(1);
});
+ expect(result.current[0].status).toBe('uninterested');
});
it('Should have active state if available in the activeAlertManagers', async () => {
@@ -61,11 +57,9 @@ describe('useExternalDataSourceAlertmanagers', () => {
const { result } = renderHook(() => useExternalDataSourceAlertmanagers(), { wrapper: TestProvider });
await waitFor(() => {
// Assert
- const { current } = result;
-
- expect(current).toHaveLength(1);
- expect(current[0].status).toBe('active');
+ expect(result.current).toHaveLength(1);
});
+ expect(result.current[0].status).toBe('active');
});
it('Should have dropped state if available in the droppedAlertManagers', async () => {
@@ -83,11 +77,9 @@ describe('useExternalDataSourceAlertmanagers', () => {
await waitFor(() => {
// Assert
- const { current } = result;
-
- expect(current).toHaveLength(1);
- expect(current[0].status).toBe('dropped');
+ expect(result.current).toHaveLength(1);
});
+ expect(result.current[0].status).toBe('dropped');
});
it('Should have pending state if not available neither in dropped nor in active alertManagers', async () => {
@@ -105,11 +97,9 @@ describe('useExternalDataSourceAlertmanagers', () => {
await waitFor(() => {
// Assert
- const { current } = result;
-
- expect(current).toHaveLength(1);
- expect(current[0].status).toBe('pending');
+ expect(result.current).toHaveLength(1);
});
+ expect(result.current[0].status).toBe('pending');
});
it('Should match Alertmanager url when datasource url does not have protocol specified', async () => {
@@ -127,12 +117,10 @@ describe('useExternalDataSourceAlertmanagers', () => {
await waitFor(() => {
// Assert
- const { current } = result;
-
- expect(current).toHaveLength(1);
- expect(current[0].status).toBe('active');
- expect(current[0].dataSourceSettings.url).toBe('localhost:9093');
+ expect(result.current).toHaveLength(1);
});
+ expect(result.current[0].status).toBe('active');
+ expect(result.current[0].dataSourceSettings.url).toBe('localhost:9093');
});
it('Should have inconclusive state when there are many Alertmanagers of the same URL on both active and inactive', async () => {
@@ -154,8 +142,8 @@ describe('useExternalDataSourceAlertmanagers', () => {
await waitFor(() => {
// Assert
expect(result.current).toHaveLength(1);
- expect(result.current[0].status).toBe('inconclusive');
});
+ expect(result.current[0].status).toBe('inconclusive');
});
it('Should have not have inconclusive state when all Alertmanagers of the same URL are active', async () => {
@@ -177,8 +165,8 @@ describe('useExternalDataSourceAlertmanagers', () => {
await waitFor(() => {
// Assert
expect(result.current).toHaveLength(1);
- expect(result.current[0].status).toBe('active');
});
+ expect(result.current[0].status).toBe('active');
});
});
diff --git a/yarn.lock b/yarn.lock
index afe45b0b2fe..1596d9f79cf 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -285,7 +285,21 @@ __metadata:
languageName: node
linkType: hard
-"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.18.9, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.0, @babel/helper-plugin-utils@npm:^7.24.5, @babel/helper-plugin-utils@npm:^7.24.7, @babel/helper-plugin-utils@npm:^7.24.8, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3":
+"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.18.9, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.0, @babel/helper-plugin-utils@npm:^7.24.5, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3":
+ version: 7.24.5
+ resolution: "@babel/helper-plugin-utils@npm:7.24.5"
+ checksum: 10/6e11ca5da73e6bd366848236568c311ac10e433fc2034a6fe6243af28419b07c93b4386f87bbc940aa058b7c83f370ef58f3b0fd598106be040d21a3d1c14276
+ languageName: node
+ linkType: hard
+
+"@babel/helper-plugin-utils@npm:^7.24.7":
+ version: 7.24.7
+ resolution: "@babel/helper-plugin-utils@npm:7.24.7"
+ checksum: 10/dad51622f0123fdba4e2d40a81a6b7d6ef4b1491b2f92fd9749447a36bde809106cf117358705057a2adc8fd73d5dc090222e0561b1213dae8601c8367f5aac8
+ languageName: node
+ linkType: hard
+
+"@babel/helper-plugin-utils@npm:^7.24.8":
version: 7.24.8
resolution: "@babel/helper-plugin-utils@npm:7.24.8"
checksum: 10/adbc9fc1142800a35a5eb0793296924ee8057fe35c61657774208670468a9fbfbb216f2d0bc46c680c5fefa785e5ff917cc1674b10bd75cdf9a6aa3444780630
@@ -347,6 +361,13 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-string-parser@npm:^7.24.7":
+ version: 7.24.7
+ resolution: "@babel/helper-string-parser@npm:7.24.7"
+ checksum: 10/603d8d962bbe89907aa99a8f19a006759ab7b2464615f20a6a22e3e2e8375af37ddd0e5175c9e622e1c4b2d83607ffb41055a59d0ce34404502af30fde573a5c
+ languageName: node
+ linkType: hard
+
"@babel/helper-string-parser@npm:^7.24.8":
version: 7.24.8
resolution: "@babel/helper-string-parser@npm:7.24.8"
@@ -1605,7 +1626,18 @@ __metadata:
languageName: node
linkType: hard
-"@babel/types@npm:^7.0.0, @babel/types@npm:^7.18.9, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.3, @babel/types@npm:^7.22.5, @babel/types@npm:^7.24.0, @babel/types@npm:^7.24.7, @babel/types@npm:^7.24.8, @babel/types@npm:^7.24.9, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3":
+"@babel/types@npm:^7.0.0, @babel/types@npm:^7.18.9, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.3, @babel/types@npm:^7.22.5, @babel/types@npm:^7.24.0, @babel/types@npm:^7.24.7, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3":
+ version: 7.24.7
+ resolution: "@babel/types@npm:7.24.7"
+ dependencies:
+ "@babel/helper-string-parser": "npm:^7.24.7"
+ "@babel/helper-validator-identifier": "npm:^7.24.7"
+ to-fast-properties: "npm:^2.0.0"
+ checksum: 10/ad3c8c0d6fb4acb0bb74bb5b4bb849b181bf6185677ef9c59c18856c81e43628d0858253cf232f0eca806f02e08eff85a1d3e636a3e94daea737597796b0b430
+ languageName: node
+ linkType: hard
+
+"@babel/types@npm:^7.24.8, @babel/types@npm:^7.24.9":
version: 7.24.9
resolution: "@babel/types@npm:7.24.9"
dependencies:
@@ -2460,7 +2492,16 @@ __metadata:
languageName: node
linkType: hard
-"@floating-ui/dom@npm:^1.0.0, @floating-ui/dom@npm:^1.0.1":
+"@floating-ui/core@npm:^1.6.0":
+ version: 1.6.0
+ resolution: "@floating-ui/core@npm:1.6.0"
+ dependencies:
+ "@floating-ui/utils": "npm:^0.2.1"
+ checksum: 10/d6a47cacde193cd8ccb4c268b91ccc4ca254dffaec6242b07fd9bcde526044cc976d27933a7917f9a671de0a0e27f8d358f46400677dbd0c8199de293e9746e1
+ languageName: node
+ linkType: hard
+
+"@floating-ui/dom@npm:^1.0.0":
version: 1.6.5
resolution: "@floating-ui/dom@npm:1.6.5"
dependencies:
@@ -2470,6 +2511,16 @@ __metadata:
languageName: node
linkType: hard
+"@floating-ui/dom@npm:^1.0.1":
+ version: 1.6.1
+ resolution: "@floating-ui/dom@npm:1.6.1"
+ dependencies:
+ "@floating-ui/core": "npm:^1.6.0"
+ "@floating-ui/utils": "npm:^0.2.1"
+ checksum: 10/c010feb55be37662eb4cc8d0a22e21359c25247bbdcd9557617fd305cf08c8f020435b17e4b4f410201ba9abe3a0dd96b5c42d56e85f7a5e11e7d30b85afc116
+ languageName: node
+ linkType: hard
+
"@floating-ui/react-dom@npm:^2.1.1":
version: 2.1.1
resolution: "@floating-ui/react-dom@npm:2.1.1"
@@ -2503,6 +2554,13 @@ __metadata:
languageName: node
linkType: hard
+"@floating-ui/utils@npm:^0.2.1":
+ version: 0.2.1
+ resolution: "@floating-ui/utils@npm:0.2.1"
+ checksum: 10/33c9ab346e7b05c5a1e6a95bc902aafcfc2c9d513a147e2491468843bd5607531b06d0b9aa56aa491cbf22a6c2495c18ccfc4c0344baec54a689a7bb8e4898d6
+ languageName: node
+ linkType: hard
+
"@formatjs/ecma402-abstract@npm:1.12.0":
version: 1.12.0
resolution: "@formatjs/ecma402-abstract@npm:1.12.0"
@@ -4953,7 +5011,7 @@ __metadata:
languageName: node
linkType: hard
-"@npmcli/package-json@npm:5.2.0, @npmcli/package-json@npm:^5.0.0, @npmcli/package-json@npm:^5.1.0":
+"@npmcli/package-json@npm:5.2.0, @npmcli/package-json@npm:^5.1.0":
version: 5.2.0
resolution: "@npmcli/package-json@npm:5.2.0"
dependencies:
@@ -4968,6 +5026,21 @@ __metadata:
languageName: node
linkType: hard
+"@npmcli/package-json@npm:^5.0.0":
+ version: 5.1.0
+ resolution: "@npmcli/package-json@npm:5.1.0"
+ dependencies:
+ "@npmcli/git": "npm:^5.0.0"
+ glob: "npm:^10.2.2"
+ hosted-git-info: "npm:^7.0.0"
+ json-parse-even-better-errors: "npm:^3.0.0"
+ normalize-package-data: "npm:^6.0.0"
+ proc-log: "npm:^4.0.0"
+ semver: "npm:^7.5.3"
+ checksum: 10/0e5cb5eff32cf80234525160a702c91a38e4b98ab74e34e2632b43c4350dbad170bd835989cc7d6e18d24798e3242e45b60f3d5e26bd128fe1c4529931105f8e
+ languageName: node
+ linkType: hard
+
"@npmcli/promise-spawn@npm:^7.0.0":
version: 7.0.2
resolution: "@npmcli/promise-spawn@npm:7.0.2"
@@ -5833,7 +5906,7 @@ __metadata:
languageName: node
linkType: hard
-"@radix-ui/react-portal@npm:1.0.4, @radix-ui/react-portal@npm:^1.0.1":
+"@radix-ui/react-portal@npm:1.0.4":
version: 1.0.4
resolution: "@radix-ui/react-portal@npm:1.0.4"
dependencies:
@@ -5853,6 +5926,26 @@ __metadata:
languageName: node
linkType: hard
+"@radix-ui/react-portal@npm:^1.0.1":
+ version: 1.0.3
+ resolution: "@radix-ui/react-portal@npm:1.0.3"
+ dependencies:
+ "@babel/runtime": "npm:^7.13.10"
+ "@radix-ui/react-primitive": "npm:1.0.3"
+ peerDependencies:
+ "@types/react": "*"
+ "@types/react-dom": "*"
+ react: ^16.8 || ^17.0 || ^18.0
+ react-dom: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ "@types/react-dom":
+ optional: true
+ checksum: 10/d352bcd6ad65eb43c9e0d72d0755c2aae85e03fb287770866262be3a2d5302b2885aee3cd99f2bbf62ecd14fcb1460703f1dcdc40351f77ad887b931c6f0012a
+ languageName: node
+ linkType: hard
+
"@radix-ui/react-presence@npm:1.0.1":
version: 1.0.1
resolution: "@radix-ui/react-presence@npm:1.0.1"
@@ -8980,7 +9073,16 @@ __metadata:
languageName: node
linkType: hard
-"@types/node@npm:*, @types/node@npm:20.14.13, @types/node@npm:>=13.7.0, @types/node@npm:^20.11.16":
+"@types/node@npm:*, @types/node@npm:>=13.7.0, @types/node@npm:^20.11.16":
+ version: 20.14.2
+ resolution: "@types/node@npm:20.14.2"
+ dependencies:
+ undici-types: "npm:~5.26.4"
+ checksum: 10/c38e47b190fa0a8bdfde24b036dddcf9401551f2fb170a90ff33625c7d6f218907e81c74e0fa6e394804a32623c24c60c50e249badc951007830f0d02c48ee0f
+ languageName: node
+ linkType: hard
+
+"@types/node@npm:20.14.13":
version: 20.14.13
resolution: "@types/node@npm:20.14.13"
dependencies:
@@ -9278,7 +9380,7 @@ __metadata:
languageName: node
linkType: hard
-"@types/semver@npm:7.5.8, @types/semver@npm:^7.3.4, @types/semver@npm:^7.5.0, @types/semver@npm:^7.5.8":
+"@types/semver@npm:7.5.8, @types/semver@npm:^7.3.12, @types/semver@npm:^7.3.4, @types/semver@npm:^7.5.0, @types/semver@npm:^7.5.8":
version: 7.5.8
resolution: "@types/semver@npm:7.5.8"
checksum: 10/3496808818ddb36deabfe4974fd343a78101fa242c4690044ccdc3b95dcf8785b494f5d628f2f47f38a702f8db9c53c67f47d7818f2be1b79f2efb09692e1178
@@ -9606,6 +9708,16 @@ __metadata:
languageName: node
linkType: hard
+"@typescript-eslint/scope-manager@npm:5.62.0":
+ version: 5.62.0
+ resolution: "@typescript-eslint/scope-manager@npm:5.62.0"
+ dependencies:
+ "@typescript-eslint/types": "npm:5.62.0"
+ "@typescript-eslint/visitor-keys": "npm:5.62.0"
+ checksum: 10/e827770baa202223bc0387e2fd24f630690809e460435b7dc9af336c77322290a770d62bd5284260fa881c86074d6a9fd6c97b07382520b115f6786b8ed499da
+ languageName: node
+ linkType: hard
+
"@typescript-eslint/scope-manager@npm:6.18.1":
version: 6.18.1
resolution: "@typescript-eslint/scope-manager@npm:6.18.1"
@@ -9670,6 +9782,13 @@ __metadata:
languageName: node
linkType: hard
+"@typescript-eslint/types@npm:5.62.0":
+ version: 5.62.0
+ resolution: "@typescript-eslint/types@npm:5.62.0"
+ checksum: 10/24e8443177be84823242d6729d56af2c4b47bfc664dd411a1d730506abf2150d6c31bdefbbc6d97c8f91043e3a50e0c698239dcb145b79bb6b0c34469aaf6c45
+ languageName: node
+ linkType: hard
+
"@typescript-eslint/types@npm:6.18.1":
version: 6.18.1
resolution: "@typescript-eslint/types@npm:6.18.1"
@@ -9691,6 +9810,24 @@ __metadata:
languageName: node
linkType: hard
+"@typescript-eslint/typescript-estree@npm:5.62.0":
+ version: 5.62.0
+ resolution: "@typescript-eslint/typescript-estree@npm:5.62.0"
+ dependencies:
+ "@typescript-eslint/types": "npm:5.62.0"
+ "@typescript-eslint/visitor-keys": "npm:5.62.0"
+ debug: "npm:^4.3.4"
+ globby: "npm:^11.1.0"
+ is-glob: "npm:^4.0.3"
+ semver: "npm:^7.3.7"
+ tsutils: "npm:^3.21.0"
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10/06c975eb5f44b43bd19fadc2e1023c50cf87038fe4c0dd989d4331c67b3ff509b17fa60a3251896668ab4d7322bdc56162a9926971218d2e1a1874d2bef9a52e
+ languageName: node
+ linkType: hard
+
"@typescript-eslint/typescript-estree@npm:6.18.1":
version: 6.18.1
resolution: "@typescript-eslint/typescript-estree@npm:6.18.1"
@@ -9782,6 +9919,24 @@ __metadata:
languageName: node
linkType: hard
+"@typescript-eslint/utils@npm:^5.58.0":
+ version: 5.62.0
+ resolution: "@typescript-eslint/utils@npm:5.62.0"
+ dependencies:
+ "@eslint-community/eslint-utils": "npm:^4.2.0"
+ "@types/json-schema": "npm:^7.0.9"
+ "@types/semver": "npm:^7.3.12"
+ "@typescript-eslint/scope-manager": "npm:5.62.0"
+ "@typescript-eslint/types": "npm:5.62.0"
+ "@typescript-eslint/typescript-estree": "npm:5.62.0"
+ eslint-scope: "npm:^5.1.1"
+ semver: "npm:^7.3.7"
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
+ checksum: 10/15ef13e43998a082b15f85db979f8d3ceb1f9ce4467b8016c267b1738d5e7cdb12aa90faf4b4e6dd6486c236cf9d33c463200465cf25ff997dbc0f12358550a1
+ languageName: node
+ linkType: hard
+
"@typescript-eslint/utils@npm:^6.0.0 || ^7.0.0":
version: 7.8.0
resolution: "@typescript-eslint/utils@npm:7.8.0"
@@ -9799,6 +9954,16 @@ __metadata:
languageName: node
linkType: hard
+"@typescript-eslint/visitor-keys@npm:5.62.0":
+ version: 5.62.0
+ resolution: "@typescript-eslint/visitor-keys@npm:5.62.0"
+ dependencies:
+ "@typescript-eslint/types": "npm:5.62.0"
+ eslint-visitor-keys: "npm:^3.3.0"
+ checksum: 10/dc613ab7569df9bbe0b2ca677635eb91839dfb2ca2c6fa47870a5da4f160db0b436f7ec0764362e756d4164e9445d49d5eb1ff0b87f4c058946ae9d8c92eb388
+ languageName: node
+ linkType: hard
+
"@typescript-eslint/visitor-keys@npm:6.18.1":
version: 6.18.1
resolution: "@typescript-eslint/visitor-keys@npm:6.18.1"
@@ -14011,7 +14176,7 @@ __metadata:
languageName: node
linkType: hard
-"dedent@npm:1.5.3, dedent@npm:^1.0.0":
+"dedent@npm:1.5.3":
version: 1.5.3
resolution: "dedent@npm:1.5.3"
peerDependencies:
@@ -14030,6 +14195,18 @@ __metadata:
languageName: node
linkType: hard
+"dedent@npm:^1.0.0":
+ version: 1.5.1
+ resolution: "dedent@npm:1.5.1"
+ peerDependencies:
+ babel-plugin-macros: ^3.1.0
+ peerDependenciesMeta:
+ babel-plugin-macros:
+ optional: true
+ checksum: 10/fc00a8bc3dfb7c413a778dc40ee8151b6c6ff35159d641f36ecd839c1df5c6e0ec5f4992e658c82624a1a62aaecaffc23b9c965ceb0bbf4d698bfc16469ac27d
+ languageName: node
+ linkType: hard
+
"deep-freeze@npm:0.0.1":
version: 0.0.1
resolution: "deep-freeze@npm:0.0.1"
@@ -14771,7 +14948,7 @@ __metadata:
languageName: node
linkType: hard
-"envinfo@npm:7.13.0, envinfo@npm:^7.7.3":
+"envinfo@npm:7.13.0":
version: 7.13.0
resolution: "envinfo@npm:7.13.0"
bin:
@@ -14780,6 +14957,15 @@ __metadata:
languageName: node
linkType: hard
+"envinfo@npm:^7.7.3":
+ version: 7.8.1
+ resolution: "envinfo@npm:7.8.1"
+ bin:
+ envinfo: dist/cli.js
+ checksum: 10/e7a2d71c7dfe398a4ffda0e844e242d2183ef2627f98e74e4cd71edd2af691c8707a2b34aacef92538c27b3daf9a360d32202f33c0a9f27f767c4e1c6ba8b522
+ languageName: node
+ linkType: hard
+
"eol@npm:^0.9.1":
version: 0.9.1
resolution: "eol@npm:0.9.1"
@@ -15386,7 +15572,18 @@ __metadata:
languageName: node
linkType: hard
-"eslint-scope@npm:5.1.1":
+"eslint-plugin-testing-library@npm:^6.2.2":
+ version: 6.2.2
+ resolution: "eslint-plugin-testing-library@npm:6.2.2"
+ dependencies:
+ "@typescript-eslint/utils": "npm:^5.58.0"
+ peerDependencies:
+ eslint: ^7.5.0 || ^8.0.0
+ checksum: 10/61947d0b81de1565c8627ec2d1e6636a8b6613cfe554a4671d011b3e88dfd77b498ce83b15bcf0a2df5570c44ad1d46d54058ed488f4e515d764196cbc6d65cf
+ languageName: node
+ linkType: hard
+
+"eslint-scope@npm:5.1.1, eslint-scope@npm:^5.1.1":
version: 5.1.1
resolution: "eslint-scope@npm:5.1.1"
dependencies:
@@ -17268,6 +17465,7 @@ __metadata:
eslint-plugin-no-barrel-files: "npm:^1.1.0"
eslint-plugin-react: "npm:7.34.2"
eslint-plugin-react-hooks: "npm:4.6.0"
+ eslint-plugin-testing-library: "npm:^6.2.2"
eslint-scope: "npm:^8.0.0"
eslint-webpack-plugin: "npm:4.2.0"
expose-loader: "npm:5.0.0"
@@ -18147,7 +18345,16 @@ __metadata:
languageName: node
linkType: hard
-"i18next@npm:^23.0.0, i18next@npm:^23.11.5, i18next@npm:^23.5.1":
+"i18next@npm:^23.0.0, i18next@npm:^23.5.1":
+ version: 23.11.3
+ resolution: "i18next@npm:23.11.3"
+ dependencies:
+ "@babel/runtime": "npm:^7.23.2"
+ checksum: 10/9d562ade19d0beba16683ff94967a6dedc0a32ce335d203c5a160f075ac5a9a7a9adb164085a6b7b69328568bc932a65b92664834c2bf3e15d8f3bff90f15353
+ languageName: node
+ linkType: hard
+
+"i18next@npm:^23.11.5":
version: 23.11.5
resolution: "i18next@npm:23.11.5"
dependencies:
@@ -24316,7 +24523,7 @@ __metadata:
languageName: node
linkType: hard
-"postcss-selector-parser@npm:^6.0.10, postcss-selector-parser@npm:^6.0.11, postcss-selector-parser@npm:^6.0.15, postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4, postcss-selector-parser@npm:^6.1.0":
+"postcss-selector-parser@npm:^6.0.10":
version: 6.1.1
resolution: "postcss-selector-parser@npm:6.1.1"
dependencies:
@@ -24326,6 +24533,16 @@ __metadata:
languageName: node
linkType: hard
+"postcss-selector-parser@npm:^6.0.11, postcss-selector-parser@npm:^6.0.15, postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4, postcss-selector-parser@npm:^6.1.0":
+ version: 6.1.0
+ resolution: "postcss-selector-parser@npm:6.1.0"
+ dependencies:
+ cssesc: "npm:^3.0.0"
+ util-deprecate: "npm:^1.0.2"
+ checksum: 10/2f9e5045b8bbe674fed3b79dbcd3daf21f5188cd7baf179beac513710ec3d75a8fc8184a262c3aec1c628ad3fd8bdb29c5d8530f1c9c5a61a18e1980bb000945
+ languageName: node
+ linkType: hard
+
"postcss-svgo@npm:^6.0.2":
version: 6.0.2
resolution: "postcss-svgo@npm:6.0.2"
@@ -29279,13 +29496,24 @@ __metadata:
languageName: node
linkType: hard
-"tslib@npm:^1.10.0, tslib@npm:^1.13.0":
+"tslib@npm:^1.10.0, tslib@npm:^1.13.0, tslib@npm:^1.8.1":
version: 1.14.1
resolution: "tslib@npm:1.14.1"
checksum: 10/7dbf34e6f55c6492637adb81b555af5e3b4f9cc6b998fb440dac82d3b42bdc91560a35a5fb75e20e24a076c651438234da6743d139e4feabf0783f3cdfe1dddb
languageName: node
linkType: hard
+"tsutils@npm:^3.21.0":
+ version: 3.21.0
+ resolution: "tsutils@npm:3.21.0"
+ dependencies:
+ tslib: "npm:^1.8.1"
+ peerDependencies:
+ typescript: ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
+ checksum: 10/ea036bec1dd024e309939ffd49fda7a351c0e87a1b8eb049570dd119d447250e2c56e0e6c00554e8205760e7417793fdebff752a46e573fbe07d4f375502a5b2
+ languageName: node
+ linkType: hard
+
"tuf-js@npm:^2.2.1":
version: 2.2.1
resolution: "tuf-js@npm:2.2.1"
@@ -29399,13 +29627,20 @@ __metadata:
languageName: node
linkType: hard
-"type-fest@npm:^4.18.2, type-fest@npm:^4.9.0":
+"type-fest@npm:^4.18.2":
version: 4.18.3
resolution: "type-fest@npm:4.18.3"
checksum: 10/eb750920d0ef3639177f581edd6489d972c5c5827abb602a9c9662889aad148a7d558257e36c563f1beb81a2e417faec52ecec9799b28531d8335856f91e6dff
languageName: node
linkType: hard
+"type-fest@npm:^4.9.0":
+ version: 4.10.2
+ resolution: "type-fest@npm:4.10.2"
+ checksum: 10/2b1ad1270d9fabeeb506ba831d513caeb05bfc852e5e012511d785ce9dc68d773fe0a42bddf857a362c7f3406244809c5b8a698b743bb7617d4a8c470672087f
+ languageName: node
+ linkType: hard
+
"type-is@npm:~1.6.18":
version: 1.6.18
resolution: "type-is@npm:1.6.18"