mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-11 09:51:30 +00:00
fix: show whitespace-only error on Create workspace and collection modal (#7883)
This commit is contained in:
@@ -45,23 +45,24 @@ const CreateCollection = ({ onClose, defaultLocation: propDefaultLocation, initi
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
collectionName: Yup.string()
|
||||
.min(1, 'must be at least 1 character')
|
||||
.max(255, 'must be 255 characters or less')
|
||||
.required('collection name is required'),
|
||||
.trim()
|
||||
.min(1, 'Collection name can\'t be empty')
|
||||
.max(255, 'Must be 255 characters or less')
|
||||
.required('Collection name is required'),
|
||||
collectionFolderName: Yup.string()
|
||||
.min(1, 'must be at least 1 character')
|
||||
.max(255, 'must be 255 characters or less')
|
||||
.min(1, 'Must be at least 1 character')
|
||||
.max(255, 'Must be 255 characters or less')
|
||||
.test('is-valid-collection-name', function (value) {
|
||||
const isValid = validateName(value);
|
||||
return isValid ? true : this.createError({ message: validateNameError(value) });
|
||||
})
|
||||
.required('folder name is required'),
|
||||
collectionLocation: Yup.string().min(1, 'location is required').required('location is required'),
|
||||
format: Yup.string().oneOf(['bru', 'yml'], 'invalid format').required('format is required')
|
||||
.required('Folder name is required'),
|
||||
collectionLocation: Yup.string().min(1, 'Location is required').required('Location is required'),
|
||||
format: Yup.string().oneOf(['bru', 'yml'], 'invalid format').required('Format is required')
|
||||
}),
|
||||
onSubmit: async (values) => {
|
||||
try {
|
||||
await dispatch(createCollection(values.collectionName,
|
||||
await dispatch(createCollection(values.collectionName.trim(),
|
||||
values.collectionFolderName,
|
||||
values.collectionLocation,
|
||||
{ format: values.format }));
|
||||
@@ -126,8 +127,17 @@ const CreateCollection = ({ onClose, defaultLocation: propDefaultLocation, initi
|
||||
ref={inputRef}
|
||||
className="block textbox mt-2 w-full"
|
||||
onChange={(e) => {
|
||||
const collectionName = e.target.value;
|
||||
if (!isEditing) {
|
||||
formik.setValues((values) => ({
|
||||
...values,
|
||||
collectionName,
|
||||
collectionFolderName: sanitizeName(collectionName)
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
formik.handleChange(e);
|
||||
!isEditing && formik.setFieldValue('collectionFolderName', sanitizeName(e.target.value));
|
||||
}}
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
|
||||
@@ -33,7 +33,8 @@ const CreateWorkspace = ({ onClose }) => {
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
workspaceName: Yup.string()
|
||||
.min(1, 'Must be at least 1 character')
|
||||
.trim()
|
||||
.min(1, 'Workspace name can\'t be empty')
|
||||
.max(255, 'Must be 255 characters or less')
|
||||
.required('Workspace name is required')
|
||||
.test('unique-name', 'A workspace with this name already exists', function (value) {
|
||||
@@ -58,7 +59,7 @@ const CreateWorkspace = ({ onClose }) => {
|
||||
try {
|
||||
setIsSubmitting(true);
|
||||
|
||||
await dispatch(createWorkspaceAction(values.workspaceName, values.workspaceFolderName, values.workspaceLocation));
|
||||
await dispatch(createWorkspaceAction(values.workspaceName.trim(), values.workspaceFolderName, values.workspaceLocation));
|
||||
toast.success('Workspace created!');
|
||||
onClose();
|
||||
} catch (error) {
|
||||
@@ -116,10 +117,17 @@ const CreateWorkspace = ({ onClose }) => {
|
||||
autoCapitalize="off"
|
||||
spellCheck="false"
|
||||
onChange={(e) => {
|
||||
formik.handleChange(e);
|
||||
const workspaceName = e.target.value;
|
||||
if (!isEditing) {
|
||||
formik.setFieldValue('workspaceFolderName', sanitizeName(e.target.value));
|
||||
formik.setValues((values) => ({
|
||||
...values,
|
||||
workspaceName,
|
||||
workspaceFolderName: sanitizeName(workspaceName)
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
formik.handleChange(e);
|
||||
}}
|
||||
value={formik.values.workspaceName || ''}
|
||||
/>
|
||||
|
||||
@@ -7,6 +7,52 @@ test.describe('Create collection', () => {
|
||||
await closeAllCollections(page);
|
||||
});
|
||||
|
||||
test('should show validation error for empty name in modal and keep modal open', async ({ page }) => {
|
||||
await page.getByTestId('collections-header-add-menu').click();
|
||||
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Create collection' }).click();
|
||||
|
||||
const inlineCreator = page.locator('.inline-collection-creator');
|
||||
await inlineCreator.waitFor({ state: 'visible', timeout: 5000 });
|
||||
await inlineCreator.locator('.cog-btn').click();
|
||||
|
||||
const createCollectionModal = page.locator('.bruno-modal-card').filter({ hasText: 'Create Collection' });
|
||||
await createCollectionModal.waitFor({ state: 'visible', timeout: 5000 });
|
||||
|
||||
const submitButton = createCollectionModal.getByRole('button', { name: 'Create', exact: true });
|
||||
await createCollectionModal.getByLabel('Name').fill('');
|
||||
await expect(submitButton).toBeEnabled();
|
||||
await submitButton.click();
|
||||
|
||||
await expect(createCollectionModal).toBeVisible();
|
||||
await expect(submitButton).toBeEnabled();
|
||||
await expect(createCollectionModal.getByText('Collection name is required')).toBeVisible({ timeout: 2000 });
|
||||
|
||||
await createCollectionModal.getByRole('button', { name: 'Cancel' }).click();
|
||||
});
|
||||
|
||||
test('should show validation error for whitespace-only name in modal and keep modal open', async ({ page }) => {
|
||||
await page.getByTestId('collections-header-add-menu').click();
|
||||
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Create collection' }).click();
|
||||
|
||||
const inlineCreator = page.locator('.inline-collection-creator');
|
||||
await inlineCreator.waitFor({ state: 'visible', timeout: 5000 });
|
||||
await inlineCreator.locator('.cog-btn').click();
|
||||
|
||||
const createCollectionModal = page.locator('.bruno-modal-card').filter({ hasText: 'Create Collection' });
|
||||
await createCollectionModal.waitFor({ state: 'visible', timeout: 5000 });
|
||||
|
||||
const submitButton = createCollectionModal.getByRole('button', { name: 'Create', exact: true });
|
||||
await createCollectionModal.getByLabel('Name').fill(' ');
|
||||
await expect(submitButton).toBeEnabled();
|
||||
await submitButton.click();
|
||||
|
||||
await expect(createCollectionModal).toBeVisible();
|
||||
await expect(submitButton).toBeEnabled();
|
||||
await expect(createCollectionModal.getByText('Collection name can\'t be empty')).toBeVisible({ timeout: 2000 });
|
||||
|
||||
await createCollectionModal.getByRole('button', { name: 'Cancel' }).click();
|
||||
});
|
||||
|
||||
test('Create collection and add a simple HTTP request', async ({ page, createTmpDir }) => {
|
||||
const collectionName = 'test-collection';
|
||||
const requestName = 'ping';
|
||||
|
||||
@@ -362,7 +362,7 @@ test.describe('Create Workspace', () => {
|
||||
await closeElectronApp(app);
|
||||
});
|
||||
|
||||
test('should show validation error for empty name in modal', async ({ launchElectronApp, createTmpDir }) => {
|
||||
test('should show validation error for empty name in modal and keep modal open', async ({ launchElectronApp, createTmpDir }) => {
|
||||
const wsLocation = await createTmpDir('ws-location-modal-empty');
|
||||
|
||||
const app = await launchElectronApp({ initUserDataPath, templateVars: { wsLocation } });
|
||||
@@ -376,20 +376,57 @@ test.describe('Create Workspace', () => {
|
||||
await page.locator('.cog-btn').click();
|
||||
});
|
||||
|
||||
await test.step('Clear name and try to submit', async () => {
|
||||
await test.step('Clear name and submit', async () => {
|
||||
const modal = page.locator('.bruno-modal-card').filter({ hasText: 'Create Workspace' });
|
||||
await modal.waitFor({ state: 'visible', timeout: 5000 });
|
||||
const submitButton = modal.getByRole('button', { name: 'Create Workspace' });
|
||||
|
||||
// Ensure name field is empty
|
||||
await modal.locator('#workspace-name').fill('');
|
||||
await modal.getByRole('button', { name: 'Create Workspace' }).click();
|
||||
await expect(submitButton).toBeEnabled();
|
||||
await submitButton.click();
|
||||
});
|
||||
|
||||
await test.step('Verify validation error appears and modal stays open', async () => {
|
||||
const modal = page.locator('.bruno-modal-card').filter({ hasText: 'Create Workspace' });
|
||||
const submitButton = modal.getByRole('button', { name: 'Create Workspace' });
|
||||
await expect(modal).toBeVisible();
|
||||
const error = modal.locator('.text-red-500');
|
||||
await expect(error.first()).toBeVisible({ timeout: 2000 });
|
||||
await expect(submitButton).toBeEnabled();
|
||||
await expect(modal.getByText('Workspace name is required')).toBeVisible({ timeout: 2000 });
|
||||
});
|
||||
|
||||
await closeElectronApp(app);
|
||||
});
|
||||
|
||||
test('should show validation error for whitespace-only name in modal and keep modal open', async ({ launchElectronApp, createTmpDir }) => {
|
||||
const wsLocation = await createTmpDir('ws-location-modal-whitespace');
|
||||
|
||||
const app = await launchElectronApp({ initUserDataPath, templateVars: { wsLocation } });
|
||||
const page = await app.firstWindow();
|
||||
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
|
||||
|
||||
await test.step('Start inline creation and open advanced modal', async () => {
|
||||
await page.locator('.workspace-name-container').click();
|
||||
await page.locator('.dropdown-item').filter({ hasText: 'Create workspace' }).click();
|
||||
await expect(page.locator('.workspace-name-input')).toBeVisible({ timeout: 5000 });
|
||||
await page.locator('.cog-btn').click();
|
||||
});
|
||||
|
||||
await test.step('Enter whitespace-only name and submit', async () => {
|
||||
const modal = page.locator('.bruno-modal-card').filter({ hasText: 'Create Workspace' });
|
||||
await modal.waitFor({ state: 'visible', timeout: 5000 });
|
||||
const submitButton = modal.getByRole('button', { name: 'Create Workspace' });
|
||||
|
||||
await modal.locator('#workspace-name').fill(' ');
|
||||
await expect(submitButton).toBeEnabled();
|
||||
await submitButton.click();
|
||||
});
|
||||
|
||||
await test.step('Verify validation error appears and modal stays open', async () => {
|
||||
const modal = page.locator('.bruno-modal-card').filter({ hasText: 'Create Workspace' });
|
||||
const submitButton = modal.getByRole('button', { name: 'Create Workspace' });
|
||||
await expect(modal).toBeVisible();
|
||||
await expect(submitButton).toBeEnabled();
|
||||
await expect(modal.getByText('Workspace name can\'t be empty')).toBeVisible({ timeout: 2000 });
|
||||
});
|
||||
|
||||
await closeElectronApp(app);
|
||||
|
||||
Reference in New Issue
Block a user