Skip to content

Commit

Permalink
[UI] Everest 865 monitoring validation (#78)
Browse files Browse the repository at this point in the history
  • Loading branch information
solovevayaroslavna committed Mar 19, 2024
1 parent 423a592 commit bdc2ba6
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 28 deletions.
Empty file removed public/dist/.gitkeep
Empty file.
56 changes: 40 additions & 16 deletions ui/apps/everest/.e2e/settings/monitoring-list.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { test } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { findRowAndClickActions } from '../utils/table';
const { MONITORING_URL, MONITORING_USER, MONITORING_PASSWORD } = process.env;

Expand All @@ -36,38 +36,62 @@ test.describe.serial('Monitoring List', () => {

await page.getByTestId('form-dialog-add').click();

// checking that monitoring has been added
// await findRowAndClickActions(page, monitoringEndpointName);
await expect(
page
.locator('.MuiTableRow-root')
.filter({ hasText: monitoringEndpointName })
).toBeVisible();
});

// delete, REMOVE when next test will be allowed
test('Edit Monitoring Endpoint', async ({ page }) => {
await page.goto('/settings/monitoring-endpoints');
await page.getByTestId('add-monitoring-endpoint').waitFor();

await findRowAndClickActions(page, monitoringEndpointName, 'Delete');
await page.getByTestId('confirm-dialog-delete').click();
});
// TODO functionality is broken
test.skip('Edit Monitoring Endpoint', async ({ page }) => {
await page
.locator('.MuiTableRow-root')
.filter({ hasText: monitoringEndpointName })
.getByTestId('MoreHorizIcon')
.click();

await page.getByRole('menuitem', { name: 'Edit' }).click();
await page.getByTestId('confirm-dialog-delete').click();

// filling out the form
await page.getByTestId('text-input-name').fill(monitoringEndpointName);
await expect(page.getByTestId('text-input-name')).toBeDisabled();
const namespaces = page.getByTestId('text-input-allowed-namespaces');
await namespaces.click();
await page.getByRole('option').last().click();
await page.getByRole('option').first().click();
await page.getByTestId('text-input-url').fill(MONITORING_URL);

// user can leave the credentials empty
await expect(page.getByTestId('form-dialog-edit')).toBeEnabled();

// user should fill both of credentials
await page.getByTestId('text-input-user').fill(MONITORING_USER);
await expect(page.getByTestId('form-dialog-edit')).toBeDisabled();
await expect(
page.getByText(
'Percona Everest does not store PMM credentials, so fill in both the User and Password fields.'
)
).toBeVisible();
await page.getByTestId('text-input-password').fill(MONITORING_PASSWORD);
await expect(page.getByTestId('form-dialog-edit')).toBeEnabled();
await expect(
page.getByText(
'Percona Everest does not store PMM credentials, so fill in both the User and Password fields.'
)
).not.toBeVisible();
await page.getByTestId('text-input-user').fill('');
await expect(page.getByTestId('form-dialog-edit')).toBeDisabled();
await expect(
page.getByText(
'Percona Everest does not store PMM credentials, so fill in both the User and Password fields.'
)
).toBeVisible();
await page.getByTestId('text-input-user').fill(MONITORING_USER);
await expect(page.getByTestId('form-dialog-edit')).toBeEnabled();

await page.getByTestId('form-dialog-add').click();

// checking that monitoring has been added
await page.getByTestId('form-dialog-edit').click();

// deleting the monitoring endpoint
await findRowAndClickActions(page, monitoringEndpointName, 'Delete');
await page.getByTestId('confirm-dialog-delete').click();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
EndpointFormFields,
EndpointFormType,
endpointDefaultValues,
endpointSchema,
getEndpointSchema,
} from './create-edit-modal.types';
import { Messages } from '../monitoring-endpoints.messages';
import { AutoCompleteSelectAll } from '../../../../components/auto-complete-select-all/auto-complete-select-all';
Expand All @@ -23,6 +23,8 @@ export const CreateEditEndpointModal = ({
const { data: namespaces = [], isFetching: isNamespacesFetching } =
useNamespaces();

const endpointSchema = getEndpointSchema(isEditMode);

const defaultValues = useMemo(
() =>
selectedEndpoint
Expand Down Expand Up @@ -71,13 +73,27 @@ export const CreateEditEndpointModal = ({
<TextInput
name={EndpointFormFields.user}
label={Messages.fieldLabels.user}
isRequired
isRequired={!isEditMode}
{...(isEditMode && {
controllerProps: {
rules: {
deps: [EndpointFormFields.password],
},
},
})}
/>
<TextInput
name={EndpointFormFields.password}
label={Messages.fieldLabels.password}
isRequired
isRequired={!isEditMode}
textFieldProps={{ type: 'password' }}
{...(isEditMode && {
controllerProps: {
rules: {
deps: [EndpointFormFields.user],
},
},
})}
/>
</FormDialog>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { z } from 'zod';
import { MonitoringInstance } from 'shared-types/monitoring.types';
import { rfc_123_schema } from 'utils/common-validation';
import { Messages } from '../monitoring-endpoints.messages';

export enum EndpointFormFields {
name = 'name',
Expand All @@ -18,13 +19,36 @@ export interface CreateEditEndpointModalProps {
isLoading?: boolean;
}

export const endpointSchema = z.object({
[EndpointFormFields.name]: rfc_123_schema('endpoint name'),
[EndpointFormFields.namespaces]: z.array(z.string()).nonempty(),
[EndpointFormFields.url]: z.string().min(1).url(),
[EndpointFormFields.user]: z.string().min(1),
[EndpointFormFields.password]: z.string().min(1),
});
export const getEndpointSchema = (isEditMode: boolean) =>
z
.object({
[EndpointFormFields.name]: rfc_123_schema('endpoint name'),
[EndpointFormFields.namespaces]: z.array(z.string()).nonempty(),
[EndpointFormFields.url]: z.string().min(1).url(),
...(isEditMode
? {
[EndpointFormFields.user]: z.string(),
[EndpointFormFields.password]: z.string(),
}
: {
[EndpointFormFields.user]: z.string().min(1),
[EndpointFormFields.password]: z.string().min(1),
}),
})
.superRefine((arg, ctx) => {
const hasUser = !!arg.user;
const hasPassword = !!arg.password;

if (hasUser !== hasPassword) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: [
arg.user ? EndpointFormFields.password : EndpointFormFields.user,
],
message: Messages.helperText.credentials,
});
}
});

export const endpointDefaultValues = {
[EndpointFormFields.name]: '',
Expand All @@ -34,4 +58,4 @@ export const endpointDefaultValues = {
[EndpointFormFields.password]: '',
};

export type EndpointFormType = z.infer<typeof endpointSchema>;
export type EndpointFormType = z.infer<ReturnType<typeof getEndpointSchema>>;
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,7 @@ export const Messages = {
namespaces: 'Namespaces',
helperText: {
namespaces: 'Select in which namespaces this endpoint should be available.',
credentials:
'Percona Everest does not store PMM credentials, so fill in both the User and Password fields.',
},
};
2 changes: 1 addition & 1 deletion ui/packages/ui-lib/src/form/inputs/text/text.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { Control, UseControllerProps } from 'react-hook-form';

export type TextInputProps = {
control?: Control;
controllerProps?: UseControllerProps;
controllerProps?: Omit<UseControllerProps, 'name'>;
name: string;
label?: string;
labelProps?: LabeledContentProps;
Expand Down

0 comments on commit bdc2ba6

Please sign in to comment.