diff --git a/packages/bruno-app/src/components/Modal/StyledWrapper.js b/packages/bruno-app/src/components/Modal/StyledWrapper.js
index 7f157dd74..5e6d44f44 100644
--- a/packages/bruno-app/src/components/Modal/StyledWrapper.js
+++ b/packages/bruno-app/src/components/Modal/StyledWrapper.js
@@ -28,8 +28,8 @@ const Wrapper = styled.div`
.bruno-modal-card {
animation-duration: 0.85s;
animation-delay: 0.1s;
- background: var(--color-background-top);
- border-radius: var(--border-radius);
+ background: ${(props) => props.theme.modal.body.bg};
+ border-radius: ${(props) => props.theme.border.radius.base};
position: relative;
z-index: 11;
max-width: calc(100% - var(--spacing-base-unit));
@@ -68,25 +68,37 @@ const Wrapper = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
- text-transform: uppercase;
color: ${(props) => props.theme.modal.title.color};
background-color: ${(props) => props.theme.modal.title.bg};
- font-size: ${(props) => props.theme.font.size.sm};
- padding: 12px;
+ font-size: ${(props) => props.theme.font.size.md};
+ padding: 0.5rem 1rem;
font-weight: 500;
- border-top-left-radius: 4px;
- border-top-right-radius: 4px;
+ border-top-left-radius: ${(props) => props.theme.border.radius.base};
+ border-top-right-radius: ${(props) => props.theme.border.radius.base};
+
+ .bruno-modal-header-title {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ }
.close {
- font-size: 1.3rem;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 24px;
+ height: 24px;
+ margin-right: -0.5rem;
+ font-size: 1.125rem;
line-height: 1;
- color: ${(props) => props.theme.modal.iconColor};
- text-shadow: 0 1px 0 #fff;
- opacity: 0.5;
- margin-top: -2px;
+ color: ${(props) => props.theme.modal.title.color};
+ border-radius: ${(props) => props.theme.border.radius.sm};
+ opacity: 0.7;
+ transition: opacity 0.2s ease, background-color 0.2s ease;
&:hover {
- opacity: 0.8;
+ opacity: 1;
+ background-color: ${(props) => props.theme.modal.closeButton.hoverBg};
}
}
}
@@ -104,7 +116,7 @@ const Wrapper = styled.div`
outline: none;
box-shadow: none;
transition: border-color ease-in-out 0.1s;
- border-radius: 3px;
+ border-radius: ${(props) => props.theme.border.radius.sm};
background-color: ${(props) => props.theme.modal.input.bg};
border: 1px solid ${(props) => props.theme.modal.input.border};
@@ -144,14 +156,14 @@ const Wrapper = styled.div`
.bruno-modal-footer {
background-color: ${(props) => props.theme.modal.body.bg};
- border-bottom-left-radius: 3px;
- border-bottom-right-radius: 3px;
+ border-bottom-left-radius: ${(props) => props.theme.border.radius.base};
+ border-bottom-right-radius: ${(props) => props.theme.border.radius.base};
}
&.modal-footer-none {
.bruno-modal-content {
- border-bottom-left-radius: 4px;
- border-bottom-right-radius: 4px;
+ border-bottom-left-radius: ${(props) => props.theme.border.radius.base};
+ border-bottom-right-radius: ${(props) => props.theme.border.radius.base};
}
}
`;
diff --git a/packages/bruno-app/src/components/Modal/index.js b/packages/bruno-app/src/components/Modal/index.js
index 7839c2dbf..c9ebbb3dc 100644
--- a/packages/bruno-app/src/components/Modal/index.js
+++ b/packages/bruno-app/src/components/Modal/index.js
@@ -10,7 +10,7 @@ const ModalHeader = ({ title, handleCancel, customHeader, hideClose }) => (
{customHeader ? customHeader : <>{title ?
{title}
: null}>}
{handleCancel && !hideClose ? (
// TODO: Remove data-test-id and use data-testid instead across the codebase.
- handleCancel() : null} data-test-id="modal-close-button" data-testid="modal-close-button">
+
handleCancel() : null} data-testid="modal-close-button">
×
) : null}
diff --git a/packages/bruno-app/src/components/Preferences/Beta/index.js b/packages/bruno-app/src/components/Preferences/Beta/index.js
index 0387dc486..f9722c124 100644
--- a/packages/bruno-app/src/components/Preferences/Beta/index.js
+++ b/packages/bruno-app/src/components/Preferences/Beta/index.js
@@ -1,9 +1,10 @@
-import React from 'react';
+import React, { useEffect, useCallback } from 'react';
import { useFormik } from 'formik';
import { useSelector, useDispatch } from 'react-redux';
import { savePreferences } from 'providers/ReduxStore/slices/app';
import StyledWrapper from './StyledWrapper';
import * as Yup from 'yup';
+import debounce from 'lodash/debounce';
import toast from 'react-hot-toast';
import { IconFlask } from '@tabler/icons';
import get from 'lodash/get';
@@ -56,19 +57,37 @@ const Beta = ({ close }) => {
}
});
- const handleSave = (newBetaPreferences) => {
+ const handleSave = useCallback((newBetaPreferences) => {
dispatch(
savePreferences({
...preferences,
beta: newBetaPreferences
})
)
- .then(() => {
- toast.success('Beta preferences saved successfully');
- close();
- })
.catch((err) => console.log(err) && toast.error('Failed to update beta preferences'));
- };
+ }, [dispatch, preferences]);
+
+ const debouncedSave = useCallback(
+ debounce((values) => {
+ betaSchema.validate(values, { abortEarly: true })
+ .then((validatedValues) => {
+ handleSave(validatedValues);
+ })
+ .catch((error) => {
+ });
+ }, 500),
+ [handleSave, betaSchema]
+ );
+
+ // Auto-save when form values change
+ useEffect(() => {
+ if (formik.dirty && formik.isValid) {
+ debouncedSave(formik.values);
+ }
+ return () => {
+ debouncedSave.cancel();
+ };
+ }, [formik.values, formik.dirty, formik.isValid, debouncedSave]);
const hasAnyBetaFeatures = BETA_FEATURES.length > 0;
@@ -113,12 +132,6 @@ const Beta = ({ close }) => {
No beta features are currently available
)}
-
-
-
- Save
-
-
);
diff --git a/packages/bruno-app/src/components/Preferences/Display/Font/index.js b/packages/bruno-app/src/components/Preferences/Display/Font/index.js
index 69e25a3db..6759db71e 100644
--- a/packages/bruno-app/src/components/Preferences/Display/Font/index.js
+++ b/packages/bruno-app/src/components/Preferences/Display/Font/index.js
@@ -1,5 +1,6 @@
-import React, { useState } from 'react';
+import React, { useState, useEffect, useCallback, useRef } from 'react';
import get from 'lodash/get';
+import debounce from 'lodash/debounce';
import { useSelector, useDispatch } from 'react-redux';
import { savePreferences } from 'providers/ReduxStore/slices/app';
import StyledWrapper from './StyledWrapper';
@@ -8,6 +9,7 @@ import toast from 'react-hot-toast';
const Font = ({ close }) => {
const dispatch = useDispatch();
const preferences = useSelector((state) => state.app.preferences);
+ const isInitialMount = useRef(true);
const [codeFont, setCodeFont] = useState(get(preferences, 'font.codeFont', 'default'));
const [codeFontSize, setCodeFontSize] = useState(get(preferences, 'font.codeFontSize', '13'));
@@ -22,22 +24,37 @@ const Font = ({ close }) => {
setCodeFontSize(clampedSize);
};
- const handleSave = () => {
+ const handleSave = useCallback((font, fontSize) => {
dispatch(
savePreferences({
...preferences,
font: {
- codeFont,
- codeFontSize
+ codeFont: font,
+ codeFontSize: fontSize
}
})
- ).then(() => {
- toast.success('Preferences saved successfully');
- close();
- }).catch(() => {
+ ).catch(() => {
toast.error('Failed to save preferences');
});
- };
+ }, [dispatch, preferences]);
+
+ const debouncedSave = useCallback(
+ debounce((font, fontSize) => {
+ handleSave(font, fontSize);
+ }, 500),
+ [handleSave]
+ );
+
+ useEffect(() => {
+ if (isInitialMount.current) {
+ isInitialMount.current = false;
+ return;
+ }
+ debouncedSave(codeFont, codeFontSize);
+ return () => {
+ debouncedSave.cancel();
+ };
+ }, [codeFont, codeFontSize, debouncedSave]);
return (
@@ -68,12 +85,6 @@ const Font = ({ close }) => {
/>
-
-
-
- Save
-
-
);
};
diff --git a/packages/bruno-app/src/components/Preferences/General/index.js b/packages/bruno-app/src/components/Preferences/General/index.js
index 96b66d7aa..da7b7dc57 100644
--- a/packages/bruno-app/src/components/Preferences/General/index.js
+++ b/packages/bruno-app/src/components/Preferences/General/index.js
@@ -1,5 +1,6 @@
-import React, { useRef } from 'react';
+import React, { useRef, useEffect, useCallback } from 'react';
import get from 'lodash/get';
+import debounce from 'lodash/debounce';
import { useFormik } from 'formik';
import { useSelector, useDispatch } from 'react-redux';
import { savePreferences } from 'providers/ReduxStore/slices/app';
@@ -95,7 +96,7 @@ const General = ({ close }) => {
}
});
- const handleSave = (newPreferences) => {
+ const handleSave = useCallback((newPreferences) => {
dispatch(
savePreferences({
...preferences,
@@ -123,12 +124,29 @@ const General = ({ close }) => {
defaultCollectionLocation: newPreferences.defaultCollectionLocation
}
}))
- .then(() => {
- toast.success('Preferences saved successfully');
- close();
- })
.catch((err) => console.log(err) && toast.error('Failed to update preferences'));
- };
+ }, [dispatch, preferences]);
+
+ const debouncedSave = useCallback(
+ debounce((values) => {
+ preferencesSchema.validate(values, { abortEarly: true })
+ .then((validatedValues) => {
+ handleSave(validatedValues);
+ })
+ .catch((error) => {
+ });
+ }, 500),
+ [handleSave]
+ );
+
+ useEffect(() => {
+ if (formik.dirty && formik.isValid) {
+ debouncedSave(formik.values);
+ }
+ return () => {
+ debouncedSave.cancel();
+ };
+ }, [formik.values, formik.dirty, formik.isValid, debouncedSave]);
const addCaCertificate = (e) => {
const filePath = window?.ipcRenderer?.getFilePath(e?.target?.files?.[0]);
@@ -366,11 +384,6 @@ const General = ({ close }) => {
{formik.touched.defaultCollectionLocation && formik.errors.defaultCollectionLocation ? (
{formik.errors.defaultCollectionLocation}
) : null}
-
-
- Save
-
-
);
diff --git a/packages/bruno-app/src/components/Preferences/ProxySettings/index.js b/packages/bruno-app/src/components/Preferences/ProxySettings/index.js
index 2b411adec..3539b42dc 100644
--- a/packages/bruno-app/src/components/Preferences/ProxySettings/index.js
+++ b/packages/bruno-app/src/components/Preferences/ProxySettings/index.js
@@ -1,6 +1,7 @@
-import React, { useEffect } from 'react';
+import React, { useEffect, useCallback } from 'react';
import { useFormik } from 'formik';
import * as Yup from 'yup';
+import debounce from 'lodash/debounce';
import toast from 'react-hot-toast';
import { savePreferences } from 'providers/ReduxStore/slices/app';
@@ -74,7 +75,7 @@ const ProxySettings = ({ close }) => {
}
});
- const onUpdate = (values) => {
+ const onUpdate = useCallback((values) => {
proxySchema
.validate(values, { abortEarly: true })
.then((validatedProxy) => {
@@ -83,18 +84,20 @@ const ProxySettings = ({ close }) => {
...preferences,
proxy: validatedProxy
})
- ).then(() => {
- toast.success('Preferences saved successfully');
- close();
- }).catch(() => {
+ ).catch(() => {
toast.error('Failed to save preferences');
});
})
.catch((error) => {
- let errMsg = error.message || 'Preferences validation error';
- toast.error(errMsg);
});
- };
+ }, [dispatch, preferences, proxySchema]);
+
+ const debouncedSave = useCallback(
+ debounce((values) => {
+ onUpdate(values);
+ }, 500),
+ [onUpdate]
+ );
const [passwordVisible, setPasswordVisible] = useState(false);
@@ -113,6 +116,15 @@ const ProxySettings = ({ close }) => {
});
}, [preferences]);
+ useEffect(() => {
+ if (formik.dirty) {
+ debouncedSave(formik.values);
+ }
+ return () => {
+ debouncedSave.cancel();
+ };
+ }, [formik.values, formik.dirty, debouncedSave]);
+
return (
);
diff --git a/packages/bruno-app/src/components/Preferences/StyledWrapper.js b/packages/bruno-app/src/components/Preferences/StyledWrapper.js
index f43047925..caaf3b54e 100644
--- a/packages/bruno-app/src/components/Preferences/StyledWrapper.js
+++ b/packages/bruno-app/src/components/Preferences/StyledWrapper.js
@@ -2,14 +2,20 @@ import styled from 'styled-components';
const StyledWrapper = styled.div`
div.tabs {
+ padding: 8px;
+ min-width: 160px;
+
div.tab {
+ display: flex;
+ align-items: center;
+ gap: 8px;
width: 100%;
- min-width: 120px;
- padding: 7px 10px;
+ padding: 6px 10px;
border: none;
- border-bottom: solid 2px transparent;
- color: var(--color-tab-inactive);
+ border-radius: ${(props) => props.theme.border.radius.sm};
+ color: ${(props) => props.theme.colors.text.muted};
cursor: pointer;
+ transition: background-color 0.15s ease;
&:focus,
&:active,
@@ -21,18 +27,36 @@ const StyledWrapper = styled.div`
}
&.active {
- color: ${(props) => props.theme.sidebar.color} !important;
- background: ${(props) => props.theme.sidebar.collection.item.bg};
+ color: ${(props) => props.theme.text} !important;
+ background: ${(props) => props.theme.modal.title.bg};
&:hover {
- background: ${(props) => props.theme.sidebar.collection.item.bg} !important;
+ background: ${(props) => props.theme.modal.title.bg} !important;
}
}
}
}
section.tab-panel {
- min-height: 300px;
+ min-height: 70vh;
+ max-height: 70vh;
+ overflow-y: auto;
+ max-width: 50vw;
+ }
+
+ input[type="checkbox"],
+ input[type="radio"] {
+ accent-color: ${(props) => props.theme.workspace.accent};
+ cursor: pointer;
+ }
+
+ .section-header {
+ font-size: ${(props) => props.theme.font.size.sm};
+ color: ${(props) => props.theme.colors.text.muted};
+ font-weight: 500;
+ margin-bottom: 8px;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
}
`;
diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/StyledWrapper.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/StyledWrapper.js
new file mode 100644
index 000000000..a61236286
--- /dev/null
+++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/StyledWrapper.js
@@ -0,0 +1,24 @@
+import styled from 'styled-components';
+
+const StyledWrapper = styled.div`
+ .collection-info-card {
+ background-color: ${(props) => props.theme.modal.title.bg};
+ border-radius: 4px;
+ padding: 12px;
+ }
+ .collection-name {
+ font-weight: 500;
+ color: ${(props) => props.theme.text};
+ margin-bottom: 4px;
+ &:hover {
+ background: none;
+ }
+ }
+ .collection-path {
+ font-size: ${(props) => props.theme.font.size.sm};
+ color: ${(props) => props.theme.colors.text.muted};
+ word-break: break-all;
+ }
+`;
+
+export default StyledWrapper;
diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/index.js
index 49fc910f4..24b353210 100644
--- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/index.js
+++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/index.js
@@ -2,11 +2,12 @@ import React, { useMemo } from 'react';
import toast from 'react-hot-toast';
import Modal from 'components/Modal';
import { useDispatch, useSelector } from 'react-redux';
-import { IconFiles } from '@tabler/icons';
+import { IconAlertCircle } from '@tabler/icons';
import { removeCollection } from 'providers/ReduxStore/slices/collections/actions';
import { findCollectionByUid, flattenItems, isItemARequest, hasRequestChanges } from 'utils/collections/index';
import filter from 'lodash/filter';
import ConfirmCollectionCloseDrafts from './ConfirmCollectionCloseDrafts';
+import StyledWrapper from './StyledWrapper';
const RemoveCollection = ({ onClose, collectionUid }) => {
const dispatch = useDispatch();
@@ -42,21 +43,35 @@ const RemoveCollection = ({ onClose, collectionUid }) => {
return ;
}
+ const customHeader = (
+
+
+ Remove Collection
+
+ );
+
// Otherwise, show the standard remove confirmation modal
return (
-
-
-
- {collection.name}
-
- {collection.pathname}
-
- Are you sure you want to remove collection {collection.name} from this workspace?
-
-
- The collection files will remain on disk and can be re-added to this or another workspace later.
-
-
+
+
+ Are you sure you want to close following collection in Bruno?
+
+
{collection.name}
+
{collection.pathname}
+
+
+ It will still be available in the filesystem at the above location and can be re-opened later.
+
+
+
);
};
diff --git a/packages/bruno-app/src/components/Sidebar/Collections/RemoveCollectionsModal/index.js b/packages/bruno-app/src/components/Sidebar/Collections/RemoveCollectionsModal/index.js
index 5d6f32b53..d52d9e893 100644
--- a/packages/bruno-app/src/components/Sidebar/Collections/RemoveCollectionsModal/index.js
+++ b/packages/bruno-app/src/components/Sidebar/Collections/RemoveCollectionsModal/index.js
@@ -255,7 +255,7 @@ const RemoveCollectionsModal = ({ collectionUids, onClose }) => {
Collections will be removed from the current workspace but will still be available in the file system and can be re-opened later.
-
+
Cancel
diff --git a/packages/bruno-app/src/themes/dark.js b/packages/bruno-app/src/themes/dark.js
index 50d2de7ae..b7c9c322a 100644
--- a/packages/bruno-app/src/themes/dark.js
+++ b/packages/bruno-app/src/themes/dark.js
@@ -313,6 +313,9 @@ const darkTheme = {
},
backdrop: {
opacity: 0.2
+ },
+ closeButton: {
+ hoverBg: 'rgba(255, 255, 255, 0.1)'
}
},
diff --git a/packages/bruno-app/src/themes/light.js b/packages/bruno-app/src/themes/light.js
index 745befc1c..b13ba6f27 100644
--- a/packages/bruno-app/src/themes/light.js
+++ b/packages/bruno-app/src/themes/light.js
@@ -1,5 +1,5 @@
const colors = {
- BRAND: '#cf8730',
+ BRAND: '#c7822e',
TEXT: 'rgb(52, 52, 52)',
TEXT_MUTED: '#838383',
TEXT_LINK: '#1663bb',
@@ -9,7 +9,7 @@ const colors = {
BLACK: '#000',
SLATE_BLACK: '#343434',
GREEN: '#047857',
- YELLOW: '#cf8730',
+ YELLOW: '#c7822e',
GRAY_1: '#f8f8f8',
GRAY_2: '#f3f3f3',
@@ -318,6 +318,9 @@ const lightTheme = {
},
backdrop: {
opacity: 0.4
+ },
+ closeButton: {
+ hoverBg: 'rgba(0, 0, 0, 0.08)'
}
},
@@ -351,7 +354,7 @@ const lightTheme = {
active: {
fontWeight: 400,
color: colors.SLATE_BLACK,
- border: '#cf8730'
+ border: '#c7822e'
},
secondary: {
active: {
diff --git a/tests/import/file-types/file-input-acceptance.spec.ts b/tests/import/file-types/file-input-acceptance.spec.ts
index d386f8d78..841a7651f 100644
--- a/tests/import/file-types/file-input-acceptance.spec.ts
+++ b/tests/import/file-types/file-input-acceptance.spec.ts
@@ -16,6 +16,6 @@ test.describe('File Input Acceptance', () => {
expect(acceptValue).toContain('.yml');
// Cleanup: close any open modals
- await page.locator('[data-test-id="modal-close-button"]').click();
+ await page.getByTestId('modal-close-button').click();
});
});
diff --git a/tests/import/file-types/invalid-file-handling.spec.ts b/tests/import/file-types/invalid-file-handling.spec.ts
index b2eb6162f..f8346f6f3 100644
--- a/tests/import/file-types/invalid-file-handling.spec.ts
+++ b/tests/import/file-types/invalid-file-handling.spec.ts
@@ -22,6 +22,6 @@ test.describe('Invalid File Handling', () => {
expect(hasError).toBe(true);
// Cleanup: close any open modals
- await page.locator('[data-test-id="modal-close-button"]').click();
+ await page.getByTestId('modal-close-button').click();
});
});
diff --git a/tests/import/insomnia/malformed-structure.spec.ts b/tests/import/insomnia/malformed-structure.spec.ts
index 55731b4e7..03156cd61 100644
--- a/tests/import/insomnia/malformed-structure.spec.ts
+++ b/tests/import/insomnia/malformed-structure.spec.ts
@@ -20,6 +20,6 @@ test.describe('Invalid Insomnia Collection - Malformed Structure', () => {
expect(hasError).toBe(true);
// Cleanup: close any open modals
- await page.locator('[data-test-id="modal-close-button"]').click();
+ await page.getByTestId('modal-close-button').click();
});
});
diff --git a/tests/import/openapi/malformed-yaml.spec.ts b/tests/import/openapi/malformed-yaml.spec.ts
index 9323f8260..453eedd40 100644
--- a/tests/import/openapi/malformed-yaml.spec.ts
+++ b/tests/import/openapi/malformed-yaml.spec.ts
@@ -22,6 +22,6 @@ test.describe('Invalid OpenAPI - Malformed YAML', () => {
await expect(parseError.or(importError)).toBeVisible({ timeout: 10000 });
// Cleanup: close any open modals
- await page.locator('[data-test-id="modal-close-button"]').click();
+ await page.getByTestId('modal-close-button').click();
});
});
diff --git a/tests/import/openapi/missing-info.spec.ts b/tests/import/openapi/missing-info.spec.ts
index f019a844e..8d2a82d15 100644
--- a/tests/import/openapi/missing-info.spec.ts
+++ b/tests/import/openapi/missing-info.spec.ts
@@ -19,6 +19,6 @@ test.describe('Invalid OpenAPI - Missing Info Section', () => {
await expect(errorMessage).toBeVisible({ timeout: 10000 });
// Cleanup: close any open modals
- await page.locator('[data-test-id="modal-close-button"]').click();
+ await page.getByTestId('modal-close-button').click();
});
});
diff --git a/tests/import/postman/invalid-json.spec.ts b/tests/import/postman/invalid-json.spec.ts
index 7bfe8682a..6183ca03f 100644
--- a/tests/import/postman/invalid-json.spec.ts
+++ b/tests/import/postman/invalid-json.spec.ts
@@ -21,6 +21,6 @@ test.describe('Invalid Postman Collection - Invalid JSON', () => {
expect(hasError).toBe(true);
// Cleanup: close any open modals
- await page.locator('[data-test-id="modal-close-button"]').click();
+ await page.getByTestId('modal-close-button').click();
});
});
diff --git a/tests/import/postman/invalid-missing-info.spec.ts b/tests/import/postman/invalid-missing-info.spec.ts
index 0952c573e..95141631d 100644
--- a/tests/import/postman/invalid-missing-info.spec.ts
+++ b/tests/import/postman/invalid-missing-info.spec.ts
@@ -20,6 +20,6 @@ test.describe('Invalid Postman Collection - Missing Info', () => {
expect(hasError).toBe(true);
// Cleanup: close any open modals
- await page.locator('[data-test-id="modal-close-button"]').click();
+ await page.getByTestId('modal-close-button').click();
});
});
diff --git a/tests/import/postman/invalid-schema.spec.ts b/tests/import/postman/invalid-schema.spec.ts
index 1961e5650..f1dbee6fd 100644
--- a/tests/import/postman/invalid-schema.spec.ts
+++ b/tests/import/postman/invalid-schema.spec.ts
@@ -20,6 +20,6 @@ test.describe('Invalid Postman Collection - Invalid Schema', () => {
expect(hasError).toBe(true);
// Cleanup: close any open modals
- await page.locator('[data-test-id="modal-close-button"]').click();
+ await page.getByTestId('modal-close-button').click();
});
});
diff --git a/tests/onboarding/sample-collection.spec.ts b/tests/onboarding/sample-collection.spec.ts
index 24397ce72..a0259f8c9 100644
--- a/tests/onboarding/sample-collection.spec.ts
+++ b/tests/onboarding/sample-collection.spec.ts
@@ -93,8 +93,8 @@ test.describe('Onboarding', () => {
await removeOption.click();
// Confirm removal in the modal
- const removeModal = page.getByRole('dialog').filter({ has: page.getByText('Remove Collection') });
- await removeModal.getByRole('button', { name: 'Remove' }).click();
+ await page.locator('[data-testid="close-collection-modal-title"]', { hasText: 'Remove Collection' }).waitFor({ state: 'visible' });
+ await page.locator('.bruno-modal-footer .submit').click();
// Verify collection is closed (no longer visible in sidebar)
await expect(sampleCollection).not.toBeVisible();
diff --git a/tests/preferences/autosave/autosave.spec.ts b/tests/preferences/autosave/autosave.spec.ts
index d79fc2c6c..dd70dce6f 100644
--- a/tests/preferences/autosave/autosave.spec.ts
+++ b/tests/preferences/autosave/autosave.spec.ts
@@ -43,10 +43,11 @@ test.describe('Autosave', () => {
const autoSaveCheckbox = preferencesModal.locator('#autoSaveEnabled');
await autoSaveCheckbox.check();
- // Save preferences
- await preferencesModal.locator('button[type="submit"]').click();
+ // Wait for auto-save to complete (debounce is 500ms)
+ await page.waitForTimeout(1000);
- // Wait for preferences to close
+ // Close preferences modal
+ await preferencesModal.locator('[data-testid="modal-close-button"]').click();
await expect(preferencesModal).not.toBeVisible();
});
@@ -92,10 +93,11 @@ test.describe('Autosave', () => {
const autoSaveCheckbox = preferencesModal.locator('#autoSaveEnabled');
await autoSaveCheckbox.uncheck();
- // Save preferences
- await preferencesModal.locator('button[type="submit"]').click();
+ // Wait for auto-save to complete (debounce is 500ms)
+ await page.waitForTimeout(1000);
- // Wait for preferences to close
+ // Close preferences modal
+ await preferencesModal.locator('[data-testid="modal-close-button"]').click();
await expect(preferencesModal).not.toBeVisible();
});
@@ -168,10 +170,11 @@ test.describe('Autosave', () => {
const autoSaveCheckbox = preferencesModal.locator('#autoSaveEnabled');
await autoSaveCheckbox.check();
- // Save preferences
- await preferencesModal.locator('button[type="submit"]').click();
+ // Wait for auto-save to complete (debounce is 500ms)
+ await page.waitForTimeout(1000);
- // Wait for preferences to close
+ // Close preferences modal
+ await preferencesModal.locator('[data-testid="modal-close-button"]').click();
await expect(preferencesModal).not.toBeVisible();
await page.waitForTimeout(1000);
diff --git a/tests/preferences/default-collection-location/default-collection-location.spec.js b/tests/preferences/default-collection-location/default-collection-location.spec.js
index f1076483a..5731f149e 100644
--- a/tests/preferences/default-collection-location/default-collection-location.spec.js
+++ b/tests/preferences/default-collection-location/default-collection-location.spec.js
@@ -10,7 +10,7 @@ test.describe('Default Collection Location Feature', () => {
await expect(defaultLocationInput).toHaveValue('/tmp/bruno-collections');
// close the preferences
- await page.locator('[data-test-id="modal-close-button"]').click();
+ await page.getByTestId('modal-close-button').click();
// wait for 2 seconds
await page.waitForTimeout(2000);
@@ -24,14 +24,14 @@ test.describe('Default Collection Location Feature', () => {
const defaultLocationInput = page.locator('.default-collection-location-input');
await defaultLocationInput.clear();
- // save preferences
- await page.getByRole('button', { name: 'Save' }).click();
+ // wait for auto-save to complete (debounce is 500ms)
+ await page.waitForTimeout(1000);
- // verify success message
- await expect(page.locator('text=Preferences saved successfully').first()).toBeVisible();
+ // close the preferences
+ await page.getByTestId('modal-close-button').click();
- // wait for 2 seconds
- await page.waitForTimeout(2000);
+ // wait for modal to close
+ await page.waitForTimeout(500);
});
test('Should save a valid default location', async ({ pageWithUserData: page }) => {
@@ -44,14 +44,14 @@ test.describe('Default Collection Location Feature', () => {
// fill the default location input
await defaultLocationInput.fill('/tmp/bruno-collections');
- // save preferences
- await page.getByRole('button', { name: 'Save' }).click();
+ // wait for auto-save to complete (debounce is 500ms)
+ await page.waitForTimeout(1000);
- // verify success message
- await expect(page.locator('text=Preferences saved successfully').first()).toBeVisible();
+ // close the preferences
+ await page.getByTestId('modal-close-button').click();
- // wait for 2 seconds
- await page.waitForTimeout(2000);
+ // wait for modal to close
+ await page.waitForTimeout(500);
});
test('Should use default location in Create Collection modal', async ({ pageWithUserData: page }) => {
diff --git a/tests/preferences/support-links.spec.js b/tests/preferences/support-links.spec.js
index 550b4ba02..4d9444572 100644
--- a/tests/preferences/support-links.spec.js
+++ b/tests/preferences/support-links.spec.js
@@ -23,5 +23,5 @@ test('Should verify all support links with correct URL in preference > Support t
const locator_documentation = page.getByRole('link', { name: 'Documentation', exact: true });
expect(await locator_documentation.getAttribute('href')).toEqual('https://docs.usebruno.com');
- await page.locator('[data-test-id="modal-close-button"]').click();
+ await page.getByTestId('modal-close-button').click();
});
diff --git a/tests/request/encoding/curl-encoding.spec.ts b/tests/request/encoding/curl-encoding.spec.ts
index a817081ae..5747958b0 100644
--- a/tests/request/encoding/curl-encoding.spec.ts
+++ b/tests/request/encoding/curl-encoding.spec.ts
@@ -4,7 +4,7 @@ import { closeAllCollections, createRequest } from '../../utils/page';
test.describe('Code Generation URL Encoding', () => {
test.afterEach(async ({ page }) => {
try {
- const modalCloseButton = page.locator('[data-test-id="modal-close-button"]');
+ const modalCloseButton = page.getByTestId('modal-close-button');
if (await modalCloseButton.isVisible()) {
await modalCloseButton.click();
await modalCloseButton.waitFor({ state: 'hidden' });
@@ -52,9 +52,9 @@ test.describe('Code Generation URL Encoding', () => {
expect(generatedCode).toContain('http://base.source/?name=John%20Doe');
- await page.locator('[data-test-id="modal-close-button"]').click();
+ await page.getByTestId('modal-close-button').click();
- await page.locator('[data-test-id="modal-close-button"]').waitFor({ state: 'hidden' });
+ await page.getByTestId('modal-close-button').waitFor({ state: 'hidden' });
});
test('Should generate code with proper URL encoding for encoded input', async ({
@@ -95,8 +95,8 @@ test.describe('Code Generation URL Encoding', () => {
expect(generatedCode).toContain('http://base.source/?name=John%20Doe');
- await page.locator('[data-test-id="modal-close-button"]').click();
+ await page.getByTestId('modal-close-button').click();
- await page.locator('[data-test-id="modal-close-button"]').waitFor({ state: 'hidden' });
+ await page.getByTestId('modal-close-button').waitFor({ state: 'hidden' });
});
});
diff --git a/tests/utils/page/actions.ts b/tests/utils/page/actions.ts
index 40b8f763f..7e9fe7fbb 100644
--- a/tests/utils/page/actions.ts
+++ b/tests/utils/page/actions.ts
@@ -18,10 +18,10 @@ const closeAllCollections = async (page) => {
await firstCollection.locator('.collection-actions .icon').click();
await page.locator('.dropdown-item').getByText('Remove').click();
// Wait for the remove collection modal to be visible
- await page.locator('.bruno-modal-header-title', { hasText: 'Remove Collection' }).waitFor({ state: 'visible' });
+ await page.getByTestId('close-collection-modal-title').filter({ hasText: 'Remove Collection' }).waitFor({ state: 'visible' });
await page.locator('.bruno-modal-footer .submit').click();
// Wait for the remove collection modal to be hidden
- await page.locator('.bruno-modal-header-title', { hasText: 'Remove Collection' }).waitFor({ state: 'hidden' });
+ await page.getByTestId('close-collection-modal-title').filter({ hasText: 'Remove Collection' }).waitFor({ state: 'hidden' });
}
// Wait until no collections are left open (check sidebar only)
@@ -288,9 +288,9 @@ const removeCollection = async (page: Page, collectionName: string) => {
await locators.dropdown.item('Remove').click();
// Wait for and confirm modal
- await locators.modal.title('Remove Collection').waitFor({ state: 'visible' });
+ await page.getByTestId('close-collection-modal-title').filter({ hasText: 'Remove Collection' }).waitFor({ state: 'visible' });
await locators.modal.button('Remove').click();
- await locators.modal.title('Remove Collection').waitFor({ state: 'hidden' });
+ await page.getByTestId('close-collection-modal-title').filter({ hasText: 'Remove Collection' }).waitFor({ state: 'hidden' });
// Verify collection is removed
await expect(