Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions e2e-tests/preferences/hardware-acceleration.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { test, expect } from '../../playwright';

test('Hardware acceleration preference should toggle correctly with restart notifications', async ({ page }) => {
// Wait for the page to load completely
await page.waitForLoadState('domcontentloaded');

// Open Preferences
await page.getByLabel('Open Preferences').click();

// Wait for preferences dialog to open
await page.waitForSelector('[role="dialog"]');

// Make sure we're on the General tab (should be default)
await page.getByRole('tab', { name: 'General' }).click();

// Find the hardware acceleration checkbox
const hardwareAccelerationCheckbox = page.getByRole('checkbox', { name: 'Hardware Acceleration' });

// Verify the checkbox exists
await expect(hardwareAccelerationCheckbox).toBeVisible();

// Get initial state (should be true by default, but handle dynamically)
const initialState = await hardwareAccelerationCheckbox.isChecked();

// Toggle the checkbox to opposite state
await hardwareAccelerationCheckbox.click();

// Verify the state changed
const newState = await hardwareAccelerationCheckbox.isChecked();
expect(newState).toBe(!initialState);

// Save the preferences
await page.getByRole('button', { name: 'Save' }).click();

// Wait for success message (use first() to avoid strict mode violation)
await expect(page.getByText('Preferences saved successfully').first()).toBeVisible();

// Check for restart notification (should appear when hardware acceleration changes)
const restartPattern = newState
? /Hardware acceleration enabled.*restart/
: /Hardware acceleration disabled.*restart/;
await expect(page.getByText(restartPattern).first()).toBeVisible({ timeout: 5000 });

// Close preferences dialog
await page.keyboard.press('Escape');

// Wait for dialog to close
await page.waitForSelector('[role="dialog"]', { state: 'detached' });

// Verify the setting persisted by reopening preferences
await page.getByLabel('Open Preferences').click();
await page.waitForSelector('[role="dialog"]');
await page.getByRole('tab', { name: 'General' }).click();

// Verify the checkbox maintained its new state
const persistedCheckbox = page.getByRole('checkbox', { name: 'Hardware Acceleration' });
const persistedState = await persistedCheckbox.isChecked();
expect(persistedState).toBe(newState);

// Test toggling back to original state
await persistedCheckbox.click();
await expect(persistedCheckbox).toHaveValue(initialState ? 'on' : 'off');

// Save again
await page.getByRole('button', { name: 'Save' }).click();

// Wait for success message and restart notification
await expect(page.getByText('Preferences saved successfully').first()).toBeVisible();
const backRestartPattern = initialState
? /Hardware acceleration enabled.*restart/
: /Hardware acceleration disabled.*restart/;
await expect(page.getByText(backRestartPattern).first()).toBeVisible({ timeout: 5000 });

// Close preferences dialog to clean up
await page.keyboard.press('Escape');
await page.waitForSelector('[role="dialog"]', { state: 'detached' });
});
22 changes: 21 additions & 1 deletion packages/bruno-app/src/components/Preferences/General/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const General = ({ close }) => {
}),
storeCookies: Yup.boolean(),
sendCookies: Yup.boolean(),
hardwareAcceleration: Yup.boolean(),
timeout: Yup.mixed()
.transform((value, originalValue) => {
return originalValue === '' ? undefined : value;
Expand All @@ -50,7 +51,8 @@ const General = ({ close }) => {
},
timeout: preferences.request.timeout,
storeCookies: get(preferences, 'request.storeCookies', true),
sendCookies: get(preferences, 'request.sendCookies', true)
sendCookies: get(preferences, 'request.sendCookies', true),
hardwareAcceleration: get(preferences, 'app.hardwareAcceleration', true)
},
validationSchema: preferencesSchema,
onSubmit: async (values) => {
Expand Down Expand Up @@ -79,6 +81,10 @@ const General = ({ close }) => {
timeout: newPreferences.timeout,
storeCookies: newPreferences.storeCookies,
sendCookies: newPreferences.sendCookies
},
app: {
...preferences.app,
hardwareAcceleration: newPreferences.hardwareAcceleration
}
}))
.then(() => {
Expand Down Expand Up @@ -212,6 +218,19 @@ const General = ({ close }) => {
Send Cookies automatically
</label>
</div>
<div className="flex items-center mt-2">
<input
id="hardwareAcceleration"
type="checkbox"
name="hardwareAcceleration"
checked={formik.values.hardwareAcceleration}
onChange={formik.handleChange}
className="mousetrap mr-0"
/>
<label className="block ml-2 select-none" htmlFor="hardwareAcceleration">
Hardware Acceleration
</label>
</div>
<div className="flex flex-col mt-6">
<label className="block select-none" htmlFor="timeout">
Request Timeout (in ms)
Expand All @@ -231,6 +250,7 @@ const General = ({ close }) => {
{formik.touched.timeout && formik.errors.timeout ? (
<div className="text-red-500">{formik.errors.timeout}</div>
) : null}

<div className="mt-10">
<button type="submit" className="submit btn btn-sm btn-secondary">
Save
Expand Down
9 changes: 9 additions & 0 deletions packages/bruno-app/src/providers/App/useIpcEvents.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,14 @@ const useIpcEvents = () => {
dispatch(updateGlobalEnvironments(val));
});

const removeHardwareAccelerationChangedListener = ipcRenderer.on('main:hardware-acceleration-changed', (val) => {
if (val.requiresRestart) {
toast.success(
`Hardware acceleration ${val.newValue ? 'enabled' : 'disabled'}. Please restart Bruno for this change to take effect.`,
);
}
});

const removeSnapshotHydrationListener = ipcRenderer.on('main:hydrate-app-with-ui-state-snapshot', (val) => {
dispatch(hydrateCollectionWithUiStateSnapshot(val));
});
Expand Down Expand Up @@ -205,6 +213,7 @@ const useIpcEvents = () => {
removeCookieUpdateListener();
removeSystemProxyEnvUpdatesListener();
removeGlobalEnvironmentsUpdatesListener();
removeHardwareAccelerationChangedListener();
removeSnapshotHydrationListener();
removeCollectionOauth2CredentialsUpdatesListener();
removeCollectionLoadingStateListener();
Expand Down
7 changes: 7 additions & 0 deletions packages/bruno-electron/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,16 @@ const registerGlobalEnvironmentsIpc = require('./ipc/global-environments');
const { safeParseJSON, safeStringifyJSON } = require('./utils/common');
const { getDomainsWithCookies } = require('./utils/cookies');
const { cookiesStore } = require('./store/cookies');
const { preferencesUtil } = require('./store/preferences');

const lastOpenedCollections = new LastOpenedCollections();

// Apply hardware acceleration setting before app is ready
if (!preferencesUtil.shouldUseHardwareAcceleration()) {
app.disableHardwareAcceleration();
console.log('Hardware acceleration disabled via preferences');
}

// Reference: https://content-security-policy.com/
const contentSecurityPolicy = [
"default-src 'self'",
Expand Down
13 changes: 13 additions & 0 deletions packages/bruno-electron/src/ipc/preferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,20 @@ const registerPreferencesIpc = (mainWindow, watcher, lastOpenedCollections) => {

ipcMain.handle('renderer:save-preferences', async (event, preferences) => {
try {
// Check if hardware acceleration setting changed
const currentPreferences = getPreferences();
const currentHardwareAcceleration = currentPreferences.app?.hardwareAcceleration;
const newHardwareAcceleration = preferences.app?.hardwareAcceleration;

await savePreferences(preferences);

// If hardware acceleration setting changed, notify user that restart is required
if (currentHardwareAcceleration !== newHardwareAcceleration) {
mainWindow.webContents.send('main:hardware-acceleration-changed', {
requiresRestart: true,
newValue: newHardwareAcceleration
});
}
} catch (error) {
return Promise.reject(error);
}
Expand Down
9 changes: 9 additions & 0 deletions packages/bruno-electron/src/store/preferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ const defaultPreferences = {
layout: {
responsePaneOrientation: 'horizontal'
},
app: {
hardwareAcceleration: true
},
beta: {
grpc: false
}
Expand Down Expand Up @@ -79,6 +82,9 @@ const preferencesSchema = Yup.object().shape({
layout: Yup.object({
responsePaneOrientation: Yup.string().oneOf(['horizontal', 'vertical'])
}),
app: Yup.object().shape({
hardwareAcceleration: Yup.boolean()
}).optional(),
beta: Yup.object({
grpc: Yup.boolean()
})
Expand Down Expand Up @@ -164,6 +170,9 @@ const preferencesUtil = {
getResponsePaneOrientation: () => {
return get(getPreferences(), 'layout.responsePaneOrientation', 'horizontal');
},
shouldUseHardwareAcceleration: () => {
return get(getPreferences(), 'app.hardwareAcceleration', true);
},
getSystemProxyEnvVariables: () => {
const { http_proxy, HTTP_PROXY, https_proxy, HTTPS_PROXY, no_proxy, NO_PROXY } = process.env;
return {
Expand Down