From da9b45db942daec4abb176fadab8e3a8acb6a067 Mon Sep 17 00:00:00 2001 From: shubh-bruno Date: Fri, 26 Jun 2026 13:49:43 +0530 Subject: [PATCH 1/5] fix(timeout): allow inherit in timout for yaml requests --- packages/bruno-converters/src/opencollection/items/graphql.ts | 2 +- packages/bruno-converters/src/opencollection/items/http.ts | 4 ++-- .../src/formats/yml/items/stringifyGraphQLRequest.ts | 2 +- .../src/formats/yml/items/stringifyHttpRequest.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/bruno-converters/src/opencollection/items/graphql.ts b/packages/bruno-converters/src/opencollection/items/graphql.ts index caac82de570..17b12ee861a 100644 --- a/packages/bruno-converters/src/opencollection/items/graphql.ts +++ b/packages/bruno-converters/src/opencollection/items/graphql.ts @@ -179,7 +179,7 @@ export const toOpenCollectionGraphqlItem = (item: BrunoItem): GraphQLRequest => const settings: GraphQLRequestSettings = { encodeUrl: typeof brunoSettings.encodeUrl === 'boolean' ? brunoSettings.encodeUrl : true, - timeout: typeof brunoSettings.timeout === 'number' ? brunoSettings.timeout : 0, + timeout: typeof brunoSettings.timeout === 'number' || brunoSettings.timeout === 'inherit' ? brunoSettings.timeout : 0, followRedirects: typeof brunoSettings.followRedirects === 'boolean' ? brunoSettings.followRedirects : true, maxRedirects: typeof brunoSettings.maxRedirects === 'number' ? brunoSettings.maxRedirects : 5 }; diff --git a/packages/bruno-converters/src/opencollection/items/http.ts b/packages/bruno-converters/src/opencollection/items/http.ts index 8efca076d57..0adc02943ad 100644 --- a/packages/bruno-converters/src/opencollection/items/http.ts +++ b/packages/bruno-converters/src/opencollection/items/http.ts @@ -105,7 +105,7 @@ export const fromOpenCollectionHttpItem = (ocRequest: HttpRequest): BrunoItem => if (ocRequest.settings) { const settings: BrunoHttpItemSettings = { encodeUrl: typeof ocRequest.settings.encodeUrl === 'boolean' ? ocRequest.settings.encodeUrl : true, - timeout: typeof ocRequest.settings.timeout === 'number' ? ocRequest.settings.timeout : 0, + timeout: typeof ocRequest.settings.timeout === 'number' || ocRequest.settings.timeout === 'inherit' ? ocRequest.settings.timeout : 0, followRedirects: typeof ocRequest.settings.followRedirects === 'boolean' ? ocRequest.settings.followRedirects : true, maxRedirects: typeof ocRequest.settings.maxRedirects === 'number' ? ocRequest.settings.maxRedirects : 5 }; @@ -221,7 +221,7 @@ export const toOpenCollectionHttpItem = (item: BrunoItem): HttpRequest => { const settings: HttpRequestSettings = { encodeUrl: typeof brunoSettings?.encodeUrl === 'boolean' ? brunoSettings.encodeUrl : true, - timeout: typeof brunoSettings?.timeout === 'number' ? brunoSettings.timeout : 0, + timeout: typeof brunoSettings?.timeout === 'number' || brunoSettings?.timeout === 'inherit' ? brunoSettings.timeout : 0, followRedirects: typeof brunoSettings?.followRedirects === 'boolean' ? brunoSettings.followRedirects : true, maxRedirects: typeof brunoSettings?.maxRedirects === 'number' ? brunoSettings.maxRedirects : 5 }; diff --git a/packages/bruno-filestore/src/formats/yml/items/stringifyGraphQLRequest.ts b/packages/bruno-filestore/src/formats/yml/items/stringifyGraphQLRequest.ts index 1e620223c00..d57c3fa8a5f 100644 --- a/packages/bruno-filestore/src/formats/yml/items/stringifyGraphQLRequest.ts +++ b/packages/bruno-filestore/src/formats/yml/items/stringifyGraphQLRequest.ts @@ -130,7 +130,7 @@ const stringifyGraphQLRequest = (item: BrunoItem): string => { } const timeout = httpSettings?.timeout; - if (isNumber(timeout)) { + if (isNumber(timeout) || timeout === 'inherit') { settings.timeout = timeout; } else { settings.timeout = 0; diff --git a/packages/bruno-filestore/src/formats/yml/items/stringifyHttpRequest.ts b/packages/bruno-filestore/src/formats/yml/items/stringifyHttpRequest.ts index a23305b4b8c..4e8b9ee9467 100644 --- a/packages/bruno-filestore/src/formats/yml/items/stringifyHttpRequest.ts +++ b/packages/bruno-filestore/src/formats/yml/items/stringifyHttpRequest.ts @@ -118,7 +118,7 @@ const stringifyHttpRequest = (item: BrunoItem): string => { } const timeout = httpSettings?.timeout; - if (isNumber(timeout)) { + if (isNumber(timeout) || timeout === 'inherit') { settings.timeout = timeout; } else { settings.timeout = 0; From 5f2592d2f5aedc5066f912b25e1727cea4bead90 Mon Sep 17 00:00:00 2001 From: shubh-bruno Date: Fri, 26 Jun 2026 17:42:34 +0530 Subject: [PATCH 2/5] test: re-run --- .../src/formats/yml/items/stringifyGraphQLRequest.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/bruno-filestore/src/formats/yml/items/stringifyGraphQLRequest.ts b/packages/bruno-filestore/src/formats/yml/items/stringifyGraphQLRequest.ts index d57c3fa8a5f..3007fb30f38 100644 --- a/packages/bruno-filestore/src/formats/yml/items/stringifyGraphQLRequest.ts +++ b/packages/bruno-filestore/src/formats/yml/items/stringifyGraphQLRequest.ts @@ -130,6 +130,7 @@ const stringifyGraphQLRequest = (item: BrunoItem): string => { } const timeout = httpSettings?.timeout; + if (isNumber(timeout) || timeout === 'inherit') { settings.timeout = timeout; } else { From 7a716974924fdbeee7a682a6b05372d076ce5422 Mon Sep 17 00:00:00 2001 From: shubh-bruno Date: Mon, 29 Jun 2026 13:58:01 +0530 Subject: [PATCH 3/5] test: yaml test cases for request timeout --- packages/bruno-common/src/utils/index.ts | 2 + .../src/opencollection/common/index.ts | 1 + .../src/opencollection/items/graphql.ts | 5 +- .../src/opencollection/items/http.ts | 7 +- .../yml/items/stringifyGraphQLRequest.ts | 3 +- .../formats/yml/items/stringifyHttpRequest.ts | 3 +- .../{ => requests-settings-bru}/bruno.json | 0 .../max-redirects.bru | 0 .../no-redirects.bru | 0 .../{ => requests-settings-bru}/timeout.bru | 0 .../requests-settings-yml/opencollection.yml | 6 + .../requests-settings-yml/timeout.yml | 14 ++ .../init-user-data/collection-security.json | 8 +- .../settings/init-user-data/preferences.json | 3 +- tests/request/settings/timeout.spec.ts | 163 ++++++++++++++---- 15 files changed, 168 insertions(+), 47 deletions(-) rename tests/request/settings/collection/{ => requests-settings-bru}/bruno.json (100%) rename tests/request/settings/collection/{ => requests-settings-bru}/max-redirects.bru (100%) rename tests/request/settings/collection/{ => requests-settings-bru}/no-redirects.bru (100%) rename tests/request/settings/collection/{ => requests-settings-bru}/timeout.bru (100%) create mode 100644 tests/request/settings/collection/requests-settings-yml/opencollection.yml create mode 100644 tests/request/settings/collection/requests-settings-yml/timeout.yml diff --git a/packages/bruno-common/src/utils/index.ts b/packages/bruno-common/src/utils/index.ts index f807245ed98..abff2725feb 100644 --- a/packages/bruno-common/src/utils/index.ts +++ b/packages/bruno-common/src/utils/index.ts @@ -38,3 +38,5 @@ export { BRUNO_VARIABLE_DATATYPES, isBrunoVariableDataType } from './datatype'; + +export const TIMEOUT_INHERIT = 'inherit' as const; diff --git a/packages/bruno-converters/src/opencollection/common/index.ts b/packages/bruno-converters/src/opencollection/common/index.ts index 3ef2e2e5d64..6acb59c3726 100644 --- a/packages/bruno-converters/src/opencollection/common/index.ts +++ b/packages/bruno-converters/src/opencollection/common/index.ts @@ -6,3 +6,4 @@ export { fromOpenCollectionVariables, toOpenCollectionVariables } from './variab export { fromOpenCollectionActions, toOpenCollectionActions } from './actions'; export { fromOpenCollectionScripts, toOpenCollectionScripts } from './scripts'; export { fromOpenCollectionAssertions, toOpenCollectionAssertions } from './assertions'; +export { TIMEOUT_INHERIT } from '@usebruno/common/utils'; \ No newline at end of file diff --git a/packages/bruno-converters/src/opencollection/items/graphql.ts b/packages/bruno-converters/src/opencollection/items/graphql.ts index 17b12ee861a..2dae29141d0 100644 --- a/packages/bruno-converters/src/opencollection/items/graphql.ts +++ b/packages/bruno-converters/src/opencollection/items/graphql.ts @@ -15,7 +15,8 @@ import { fromOpenCollectionActions, toOpenCollectionActions, fromOpenCollectionAssertions, - toOpenCollectionAssertions + toOpenCollectionAssertions, + TIMEOUT_INHERIT } from '../common'; import type { GraphQLRequest, @@ -179,7 +180,7 @@ export const toOpenCollectionGraphqlItem = (item: BrunoItem): GraphQLRequest => const settings: GraphQLRequestSettings = { encodeUrl: typeof brunoSettings.encodeUrl === 'boolean' ? brunoSettings.encodeUrl : true, - timeout: typeof brunoSettings.timeout === 'number' || brunoSettings.timeout === 'inherit' ? brunoSettings.timeout : 0, + timeout: typeof brunoSettings.timeout === 'number' || brunoSettings.timeout === TIMEOUT_INHERIT ? brunoSettings.timeout : 0, followRedirects: typeof brunoSettings.followRedirects === 'boolean' ? brunoSettings.followRedirects : true, maxRedirects: typeof brunoSettings.maxRedirects === 'number' ? brunoSettings.maxRedirects : 5 }; diff --git a/packages/bruno-converters/src/opencollection/items/http.ts b/packages/bruno-converters/src/opencollection/items/http.ts index 0adc02943ad..c362d0b6bce 100644 --- a/packages/bruno-converters/src/opencollection/items/http.ts +++ b/packages/bruno-converters/src/opencollection/items/http.ts @@ -15,7 +15,8 @@ import { fromOpenCollectionActions, toOpenCollectionActions, fromOpenCollectionAssertions, - toOpenCollectionAssertions + toOpenCollectionAssertions, + TIMEOUT_INHERIT } from '../common'; import type { HttpRequest, @@ -105,7 +106,7 @@ export const fromOpenCollectionHttpItem = (ocRequest: HttpRequest): BrunoItem => if (ocRequest.settings) { const settings: BrunoHttpItemSettings = { encodeUrl: typeof ocRequest.settings.encodeUrl === 'boolean' ? ocRequest.settings.encodeUrl : true, - timeout: typeof ocRequest.settings.timeout === 'number' || ocRequest.settings.timeout === 'inherit' ? ocRequest.settings.timeout : 0, + timeout: typeof ocRequest.settings.timeout === 'number' || ocRequest.settings.timeout === TIMEOUT_INHERIT ? ocRequest.settings.timeout : 0, followRedirects: typeof ocRequest.settings.followRedirects === 'boolean' ? ocRequest.settings.followRedirects : true, maxRedirects: typeof ocRequest.settings.maxRedirects === 'number' ? ocRequest.settings.maxRedirects : 5 }; @@ -221,7 +222,7 @@ export const toOpenCollectionHttpItem = (item: BrunoItem): HttpRequest => { const settings: HttpRequestSettings = { encodeUrl: typeof brunoSettings?.encodeUrl === 'boolean' ? brunoSettings.encodeUrl : true, - timeout: typeof brunoSettings?.timeout === 'number' || brunoSettings?.timeout === 'inherit' ? brunoSettings.timeout : 0, + timeout: typeof brunoSettings?.timeout === 'number' || brunoSettings?.timeout === TIMEOUT_INHERIT ? brunoSettings.timeout : 0, followRedirects: typeof brunoSettings?.followRedirects === 'boolean' ? brunoSettings.followRedirects : true, maxRedirects: typeof brunoSettings?.maxRedirects === 'number' ? brunoSettings.maxRedirects : 5 }; diff --git a/packages/bruno-filestore/src/formats/yml/items/stringifyGraphQLRequest.ts b/packages/bruno-filestore/src/formats/yml/items/stringifyGraphQLRequest.ts index 3007fb30f38..d9b20f2a410 100644 --- a/packages/bruno-filestore/src/formats/yml/items/stringifyGraphQLRequest.ts +++ b/packages/bruno-filestore/src/formats/yml/items/stringifyGraphQLRequest.ts @@ -16,6 +16,7 @@ import { toOpenCollectionVariables } from '../common/variables'; import { toOpenCollectionActions } from '../common/actions'; import { toOpenCollectionScripts } from '../common/scripts'; import { toOpenCollectionAssertions } from '../common/assertions'; +import { TIMEOUT_INHERIT } from '@usebruno/common/utils'; const stringifyGraphQLRequest = (item: BrunoItem): string => { try { @@ -131,7 +132,7 @@ const stringifyGraphQLRequest = (item: BrunoItem): string => { const timeout = httpSettings?.timeout; - if (isNumber(timeout) || timeout === 'inherit') { + if (isNumber(timeout) || timeout === TIMEOUT_INHERIT) { settings.timeout = timeout; } else { settings.timeout = 0; diff --git a/packages/bruno-filestore/src/formats/yml/items/stringifyHttpRequest.ts b/packages/bruno-filestore/src/formats/yml/items/stringifyHttpRequest.ts index 4e8b9ee9467..cd8b1e35051 100644 --- a/packages/bruno-filestore/src/formats/yml/items/stringifyHttpRequest.ts +++ b/packages/bruno-filestore/src/formats/yml/items/stringifyHttpRequest.ts @@ -18,6 +18,7 @@ import { toOpenCollectionActions } from '../common/actions'; import { toOpenCollectionScripts } from '../common/scripts'; import { toOpenCollectionAssertions } from '../common/assertions'; import { isNumber, isNonEmptyString } from '../../../utils'; +import { TIMEOUT_INHERIT } from '@usebruno/common/utils'; const stringifyHttpRequest = (item: BrunoItem): string => { try { @@ -118,7 +119,7 @@ const stringifyHttpRequest = (item: BrunoItem): string => { } const timeout = httpSettings?.timeout; - if (isNumber(timeout) || timeout === 'inherit') { + if (isNumber(timeout) || timeout === TIMEOUT_INHERIT) { settings.timeout = timeout; } else { settings.timeout = 0; diff --git a/tests/request/settings/collection/bruno.json b/tests/request/settings/collection/requests-settings-bru/bruno.json similarity index 100% rename from tests/request/settings/collection/bruno.json rename to tests/request/settings/collection/requests-settings-bru/bruno.json diff --git a/tests/request/settings/collection/max-redirects.bru b/tests/request/settings/collection/requests-settings-bru/max-redirects.bru similarity index 100% rename from tests/request/settings/collection/max-redirects.bru rename to tests/request/settings/collection/requests-settings-bru/max-redirects.bru diff --git a/tests/request/settings/collection/no-redirects.bru b/tests/request/settings/collection/requests-settings-bru/no-redirects.bru similarity index 100% rename from tests/request/settings/collection/no-redirects.bru rename to tests/request/settings/collection/requests-settings-bru/no-redirects.bru diff --git a/tests/request/settings/collection/timeout.bru b/tests/request/settings/collection/requests-settings-bru/timeout.bru similarity index 100% rename from tests/request/settings/collection/timeout.bru rename to tests/request/settings/collection/requests-settings-bru/timeout.bru diff --git a/tests/request/settings/collection/requests-settings-yml/opencollection.yml b/tests/request/settings/collection/requests-settings-yml/opencollection.yml new file mode 100644 index 00000000000..a494db4aaed --- /dev/null +++ b/tests/request/settings/collection/requests-settings-yml/opencollection.yml @@ -0,0 +1,6 @@ +opencollection: "1.0.0" + +info: + name: settings-yaml + +bundled: false diff --git a/tests/request/settings/collection/requests-settings-yml/timeout.yml b/tests/request/settings/collection/requests-settings-yml/timeout.yml new file mode 100644 index 00000000000..2e2826b325f --- /dev/null +++ b/tests/request/settings/collection/requests-settings-yml/timeout.yml @@ -0,0 +1,14 @@ +info: + name: timeout-test-yaml + type: http + seq: 1 + +http: + method: GET + url: https://testbench-sanity.usebruno.com/redirect-to-ping + auth: inherit + +settings: + followRedirects: false + maxRedirects: 0 + timeout: 5 diff --git a/tests/request/settings/init-user-data/collection-security.json b/tests/request/settings/init-user-data/collection-security.json index f60c658a5d2..bb97dbc9356 100644 --- a/tests/request/settings/init-user-data/collection-security.json +++ b/tests/request/settings/init-user-data/collection-security.json @@ -1,7 +1,13 @@ { "collections": [ { - "path": "{{projectRoot}}/tests/request/settings/collection", + "path": "{{projectRoot}}/tests/request/settings/collection/requests-settings-bru", + "securityConfig": { + "jsSandboxMode": "safe" + } + }, + { + "path": "{{projectRoot}}/tests/request/settings/collection/requests-settings-yml", "securityConfig": { "jsSandboxMode": "safe" } diff --git a/tests/request/settings/init-user-data/preferences.json b/tests/request/settings/init-user-data/preferences.json index 750c260214a..df3788b6715 100644 --- a/tests/request/settings/init-user-data/preferences.json +++ b/tests/request/settings/init-user-data/preferences.json @@ -1,7 +1,8 @@ { "maximized": false, "lastOpenedCollections": [ - "{{projectRoot}}/tests/request/settings/collection" + "{{projectRoot}}/tests/request/settings/collection/requests-settings-bru", + "{{projectRoot}}/tests/request/settings/collection/requests-settings-yml" ], "preferences": { "onboarding": { diff --git a/tests/request/settings/timeout.spec.ts b/tests/request/settings/timeout.spec.ts index e30f081057f..29d1c4d6d8b 100644 --- a/tests/request/settings/timeout.spec.ts +++ b/tests/request/settings/timeout.spec.ts @@ -1,56 +1,143 @@ -import { test, expect } from '../../../playwright'; +import { expect, Page, test } from '../../../playwright'; import { closeAllCollections, selectRequestPaneTab } from '../../utils/page'; +const setGlobalRequestTimeout = async (page: Page, value: string) => { + // Open preferences tab + await page.locator('.status-bar button[data-trigger="preferences"]').click(); + + // Navigate to General tab (default, but ensure it) + const generalTab = page.getByRole('tab', { name: 'General' }); + await expect(generalTab).toBeVisible({ timeout: 10000 }); + await generalTab.click(); + + // Update the Request Timeout (in ms) preference + const timeoutPreference = page.locator('input[name="timeout"]'); + await expect(timeoutPreference).toBeVisible({ timeout: 10000 }); + await timeoutPreference.fill(value); + await expect(timeoutPreference).toHaveValue(value, { timeout: 5000 }); + + // Closing the preferences tab unmounts the form, which flushes the debounced save immediately + const preferencesTab = page.locator('.request-tab').filter({ hasText: 'Preferences' }); + await preferencesTab.hover(); + await preferencesTab.locator('.close-icon').click({ force: true }); + await expect(preferencesTab).not.toBeVisible({ timeout: 10000 }); +}; + test.describe('Timeout Settings Tests', () => { - test('should configure and test timeout settings', async ({ - pageWithUserData: page - }) => { - // Navigate to the test collection and request - await expect(page.locator('#sidebar-collection-name').getByText('settings-test')).toBeVisible(); + test.afterEach(async ({ pageWithUserData: page }) => { + await closeAllCollections(page); + }); - await page.locator('#sidebar-collection-name').getByText('settings-test').click(); - // Navigate to thetimeout request - await page.getByRole('complementary').getByText('timeout-test').click(); + test.describe('bru request timeout settings', () => { + test('should configure and test timeout settings', async ({ + pageWithUserData: page + }) => { + // Navigate to the test collection and request + await expect(page.locator('#sidebar-collection-name').getByText('settings-test')).toBeVisible(); - // Go to Settings tab - await selectRequestPaneTab(page, 'Settings'); + await page.locator('#sidebar-collection-name').getByText('settings-test').click(); + // Navigate to thetimeout request + await page.getByRole('complementary').getByText('timeout-test').click(); - // Test Timeout Settings with custom value - const timeoutInput = page.locator('input[id="timeout"]'); - await expect(timeoutInput).toBeVisible(); + // Go to Settings tab + await selectRequestPaneTab(page, 'Settings'); - // Verify default value from .bru file (5) - await expect(timeoutInput).toHaveValue('5'); + // Test Timeout Settings with custom value + const timeoutInput = page.locator('input[id="timeout"]'); + await expect(timeoutInput).toBeVisible(); - await page.getByTestId('send-arrow-icon').click(); + // Verify default value from .bru file (5) + await expect(timeoutInput).toHaveValue('5'); - const responsePane = page.locator('.response-pane'); - await expect(responsePane).toContainText('timeout of 5ms exceeded'); + await page.getByTestId('send-arrow-icon').click(); - // Now test inherit functionality - // Click the X button to reset to inherit - const resetButton = page.locator('button[title="Reset to inherit"]'); - await expect(resetButton).toBeVisible(); - await resetButton.click(); + const responsePane = page.locator('.response-pane'); + await expect(responsePane).toContainText('timeout of 5ms exceeded'); - // After reset, should see "Inherit" button instead of input - const inheritButton = page.locator('button:has-text("Inherit")'); - await expect(inheritButton).toBeVisible(); - await expect(timeoutInput).not.toBeVisible(); + // Change the global request timeout preference that "inherit" should fall back to + await setGlobalRequestTimeout(page, '10'); - // Run the request with inherit timeout - await page.getByTestId('send-arrow-icon').click(); + // Return to the request and Settings tab + await page.getByRole('complementary').getByText('timeout-test').click(); + await selectRequestPaneTab(page, 'Settings'); - // Verify the request runs successfully with inherited timeout (should not timeout) - await expect(responsePane).toContainText('302'); + // Now test inherit functionality + // Click the X button to reset to inherit + const resetButton = page.locator('button[title="Reset to inherit"]'); + await expect(resetButton).toBeVisible(); + await resetButton.click(); - // Close without saving to avoid modifying the .bru file - await page.locator('.close-icon-container').click({ force: true }); - await page.locator('button:has-text("Don\'t Save")').first().click(); + // After reset, should see "Inherit" button instead of input + const inheritButton = page.locator('button:has-text("Inherit")'); + await expect(inheritButton).toBeVisible(); + await expect(timeoutInput).not.toBeVisible(); + + // Run the request with inherit timeout + await page.getByTestId('send-arrow-icon').click(); + + // Verify the request runs successfully with inherited timeout (should not timeout) + await expect(responsePane).toContainText('302'); + + // Close without saving to avoid modifying the .bru file + await page.locator('.close-icon-container').click({ force: true }); + await page.locator('button:has-text("Don\'t Save")').first().click(); + }); }); - test.afterEach(async ({ pageWithUserData: page }) => { - // cleanup: close all collections - await closeAllCollections(page); + test.describe('yaml request timeout settings', () => { + test('should configure and test timeout settings for yaml request', async ({ + pageWithUserData: page + }) => { + // Navigate to the yaml test collection and request + await expect(page.locator('#sidebar-collection-name').getByText('settings-yaml')).toBeVisible(); + + await page.locator('#sidebar-collection-name').getByText('settings-yaml').click(); + // Navigate to the timeout request + await page.getByRole('complementary').getByText('timeout-test-yaml').click(); + + // Go to Settings tab + await selectRequestPaneTab(page, 'Settings'); + + // Test Timeout Settings with custom value + const timeoutInput = page.locator('input[id="timeout"]'); + await expect(timeoutInput).toBeVisible(); + + // Verify default value from .yml file (5) + await expect(timeoutInput).toHaveValue('5'); + + await page.getByTestId('send-arrow-icon').click(); + + // Verify the custom timeout (5ms) is applied + const responsePane = page.locator('.response-pane'); + await expect(responsePane).toContainText('timeout of 5ms exceeded'); + + // Change the global request timeout preference that "inherit" should fall back to + await setGlobalRequestTimeout(page, '10'); + + // Return to the request and Settings tab + await page.getByRole('complementary').getByText('timeout-test-yaml').click(); + await selectRequestPaneTab(page, 'Settings'); + + // Now test inherit functionality + // Click the X button to reset to inherit + const resetButton = page.locator('button[title="Reset to inherit"]'); + await expect(resetButton).toBeVisible(); + await resetButton.click(); + + // After reset, should see "Inherit" button instead of input + const inheritButton = page.locator('button:has-text("Inherit")'); + await expect(inheritButton).toBeVisible(); + await expect(timeoutInput).not.toBeVisible(); + + // Run the request with inherit timeout + await page.getByTestId('send-arrow-icon').click(); + + // Verify the inherited timeout resolves to the new global preference (10ms), not the file value (5ms) + await expect(responsePane).toContainText('timeout of 10ms exceeded', { timeout: 15000 }); + + // Close without saving to avoid modifying the .yml file + await page.locator('.close-icon-container').click({ force: true }); + await page.locator('button:has-text("Don\'t Save")').first().click(); + }); }); }); From e0f784615d7c301f9ceb73cd5b525f3875696d3d Mon Sep 17 00:00:00 2001 From: shubh-bruno Date: Mon, 29 Jun 2026 16:38:48 +0530 Subject: [PATCH 4/5] test: re-run --- tests/request/settings/timeout.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/request/settings/timeout.spec.ts b/tests/request/settings/timeout.spec.ts index 29d1c4d6d8b..85d2898736f 100644 --- a/tests/request/settings/timeout.spec.ts +++ b/tests/request/settings/timeout.spec.ts @@ -16,7 +16,6 @@ const setGlobalRequestTimeout = async (page: Page, value: string) => { await timeoutPreference.fill(value); await expect(timeoutPreference).toHaveValue(value, { timeout: 5000 }); - // Closing the preferences tab unmounts the form, which flushes the debounced save immediately const preferencesTab = page.locator('.request-tab').filter({ hasText: 'Preferences' }); await preferencesTab.hover(); await preferencesTab.locator('.close-icon').click({ force: true }); From 7ff1b72b827618e86c3ccba0e5b3e3e6bd5d1a7e Mon Sep 17 00:00:00 2001 From: shubh-bruno Date: Mon, 29 Jun 2026 18:10:43 +0530 Subject: [PATCH 5/5] test(timeout): verify inherit persistence for bru and yml requests --- tests/request/settings/timeout.spec.ts | 70 +++++++++++++++++++++----- 1 file changed, 57 insertions(+), 13 deletions(-) diff --git a/tests/request/settings/timeout.spec.ts b/tests/request/settings/timeout.spec.ts index 85d2898736f..275a60f42a8 100644 --- a/tests/request/settings/timeout.spec.ts +++ b/tests/request/settings/timeout.spec.ts @@ -1,6 +1,12 @@ +import { execSync } from 'child_process'; +import fs from 'fs'; +import path from 'path'; import { expect, Page, test } from '../../../playwright'; import { closeAllCollections, selectRequestPaneTab } from '../../utils/page'; +const bruRequestPath = path.join(__dirname, 'collection', 'requests-settings-bru', 'timeout.bru'); +const yamlRequestPath = path.join(__dirname, 'collection', 'requests-settings-yml', 'timeout.yml'); + const setGlobalRequestTimeout = async (page: Page, value: string) => { // Open preferences tab await page.locator('.status-bar button[data-trigger="preferences"]').click(); @@ -27,6 +33,10 @@ test.describe('Timeout Settings Tests', () => { await closeAllCollections(page); }); + test.afterAll(() => { + execSync(`git checkout -- "${bruRequestPath}" "${yamlRequestPath}"`); + }); + test.describe('bru request timeout settings', () => { test('should configure and test timeout settings', async ({ pageWithUserData: page @@ -71,15 +81,32 @@ test.describe('Timeout Settings Tests', () => { await expect(inheritButton).toBeVisible(); await expect(timeoutInput).not.toBeVisible(); - // Run the request with inherit timeout - await page.getByTestId('send-arrow-icon').click(); + // Save the request so the inherit setting is serialized to the .bru file + const saveShortcut = process.platform === 'darwin' ? 'Meta+s' : 'Control+s'; + await page.keyboard.press(saveShortcut); + await expect(page.getByText('Request saved successfully')).toBeVisible(); + + // Verify persistence: the serialized file must keep timeout: inherit (not reset to a custom value) + const savedContent = fs.readFileSync(bruRequestPath, 'utf-8'); + expect(savedContent).toMatch(/timeout:\s*['"]?inherit['"]?/); + + // Reopen the request to confirm the inherit state persists in the Settings UI + const requestTab = page.locator('.request-tab').filter({ hasText: 'timeout-test' }); + await requestTab.hover(); + await requestTab.getByTestId('request-tab-close-icon').click({ force: true }); + + await page.getByRole('complementary').getByText('timeout-test').click(); + await selectRequestPaneTab(page, 'Settings'); + + // Settings UI should still show Inherit (not a custom value) after reopening + await expect(inheritButton).toBeVisible(); + await expect(timeoutInput).not.toBeVisible(); - // Verify the request runs successfully with inherited timeout (should not timeout) - await expect(responsePane).toContainText('302'); + // Run the request with the inherited timeout + await page.getByTestId('send-arrow-icon').click(); - // Close without saving to avoid modifying the .bru file - await page.locator('.close-icon-container').click({ force: true }); - await page.locator('button:has-text("Don\'t Save")').first().click(); + // Verify the inherited timeout resolves to the global preference (10ms), not the file value (5ms) + await expect(responsePane).toContainText('timeout of 10ms exceeded', { timeout: 15000 }); }); }); @@ -128,15 +155,32 @@ test.describe('Timeout Settings Tests', () => { await expect(inheritButton).toBeVisible(); await expect(timeoutInput).not.toBeVisible(); - // Run the request with inherit timeout + // Save the request so the inherit setting is serialized to the .yml file + const saveShortcut = process.platform === 'darwin' ? 'Meta+s' : 'Control+s'; + await page.keyboard.press(saveShortcut); + await expect(page.getByText('Request saved successfully')).toBeVisible(); + + // Verify YAML persistence: the serialized file must keep timeout: inherit (not reset to 0) + const savedContent = fs.readFileSync(yamlRequestPath, 'utf-8'); + expect(savedContent).toMatch(/timeout:\s*['"]?inherit['"]?/); + + // Reopen the request to confirm the inherit state persists in the Settings UI + const requestTab = page.locator('.request-tab').filter({ hasText: 'timeout-test-yaml' }); + await requestTab.hover(); + await requestTab.getByTestId('request-tab-close-icon').click({ force: true }); + + await page.getByRole('complementary').getByText('timeout-test-yaml').click(); + await selectRequestPaneTab(page, 'Settings'); + + // Settings UI should still show Inherit (not a custom value) after reopening + await expect(inheritButton).toBeVisible(); + await expect(timeoutInput).not.toBeVisible(); + + // Run the request with the inherited timeout await page.getByTestId('send-arrow-icon').click(); - // Verify the inherited timeout resolves to the new global preference (10ms), not the file value (5ms) + // Verify the inherited timeout resolves to the global preference (10ms), not the file value (5ms) await expect(responsePane).toContainText('timeout of 10ms exceeded', { timeout: 15000 }); - - // Close without saving to avoid modifying the .yml file - await page.locator('.close-icon-container').click({ force: true }); - await page.locator('button:has-text("Don\'t Save")').first().click(); }); }); });