1+ import path from 'path' ;
2+ import fs from 'fs' ;
13import { test , expect , closeElectronApp } from '../../playwright' ;
24import {
35 createCollection ,
@@ -6,6 +8,34 @@ import {
68} from '../utils/page' ;
79import { buildCommonLocators } from '../utils/page/locators' ;
810
11+ const readSnapshot = ( userDataPath : string ) => {
12+ const snapshotPath = path . join ( userDataPath , 'ui-state-snapshot.json' ) ;
13+ if ( ! fs . existsSync ( snapshotPath ) ) return null ;
14+ return JSON . parse ( fs . readFileSync ( snapshotPath , 'utf-8' ) ) ;
15+ } ;
16+
17+ const findSnapshotRequestTab = ( snapshot : any , requestName : string ) => {
18+ if ( ! snapshot || ! Array . isArray ( snapshot . collections ) ) {
19+ return null ;
20+ }
21+
22+ for ( const collection of snapshot . collections ) {
23+ if ( ! Array . isArray ( collection ?. tabs ) ) continue ;
24+
25+ const tab = collection . tabs . find ( ( candidate ) => (
26+ candidate ?. accessor === 'pathname'
27+ && typeof candidate ?. pathname === 'string'
28+ && candidate . pathname . includes ( requestName )
29+ ) ) ;
30+
31+ if ( tab ) {
32+ return tab ;
33+ }
34+ }
35+
36+ return null ;
37+ } ;
38+
939test . describe ( 'Snapshot: Request Pane Interactivity' , ( ) => {
1040 test ( 'grpc request pane tab interactivity is restored after restart' , async ( { launchElectronApp, createTmpDir } ) => {
1141 const userDataPath = await createTmpDir ( 'snap-grpc-interactivity' ) ;
@@ -105,4 +135,172 @@ test.describe('Snapshot: Request Pane Interactivity', () => {
105135 await closeElectronApp ( app2 ) ;
106136 } ) ;
107137 } ) ;
138+
139+ test ( 'grpc snapshot stores concrete type and body tab key' , async ( { launchElectronApp, createTmpDir } ) => {
140+ const userDataPath = await createTmpDir ( 'snap-grpc-snapshot-type-tab-key' ) ;
141+ const colPath = await createTmpDir ( 'col' ) ;
142+
143+ const app = await launchElectronApp ( { userDataPath } ) ;
144+ const page = await app . firstWindow ( ) ;
145+ await page . locator ( '[data-app-state="loaded"]' ) . waitFor ( { timeout : 30000 } ) ;
146+
147+ await test . step ( 'Create collection and gRPC request' , async ( ) => {
148+ await createCollection ( page , 'TestCol' , colPath ) ;
149+
150+ const locators = buildCommonLocators ( page ) ;
151+ await locators . sidebar . collection ( 'TestCol' ) . hover ( ) ;
152+ await locators . actions . collectionActions ( 'TestCol' ) . click ( ) ;
153+ await locators . dropdown . item ( 'New Request' ) . click ( ) ;
154+
155+ await page . getByTestId ( 'grpc-request' ) . click ( ) ;
156+ await page . getByTestId ( 'request-name' ) . fill ( 'ReqGrpcSnapshot' ) ;
157+ await page . getByTestId ( 'new-request-url' ) . locator ( '.CodeMirror' ) . click ( ) ;
158+ await page . keyboard . type ( 'grpc://localhost:50051' ) ;
159+ await locators . modal . button ( 'Create' ) . click ( ) ;
160+
161+ await openRequest ( page , 'TestCol' , 'ReqGrpcSnapshot' , { persist : true } ) ;
162+ await selectRequestPaneTab ( page , 'Message' ) ;
163+ } ) ;
164+
165+ await test . step ( 'Close app and verify snapshot stores grpc-request/body' , async ( ) => {
166+ await page . waitForTimeout ( 2000 ) ;
167+ await closeElectronApp ( app ) ;
168+
169+ const snapshotPath = path . join ( userDataPath , 'ui-state-snapshot.json' ) ;
170+ await expect . poll ( ( ) => fs . existsSync ( snapshotPath ) ) . toBe ( true ) ;
171+
172+ const snapshot = readSnapshot ( userDataPath ) ;
173+ const tab = findSnapshotRequestTab ( snapshot , 'ReqGrpcSnapshot' ) ;
174+ expect ( tab ) . toBeTruthy ( ) ;
175+ expect ( tab . type ) . toBe ( 'grpc-request' ) ;
176+ expect ( tab . request ?. tab ) . toBe ( 'body' ) ;
177+ } ) ;
178+
179+ await test . step ( 'Verify restore opens Message tab and avoids 404' , async ( ) => {
180+ const app2 = await launchElectronApp ( { userDataPath } ) ;
181+ const page2 = await app2 . firstWindow ( ) ;
182+ await page2 . locator ( '[data-app-state="loaded"]' ) . waitFor ( { timeout : 30000 } ) ;
183+
184+ const locators = buildCommonLocators ( page2 ) ;
185+ await expect ( locators . tabs . requestTab ( 'ReqGrpcSnapshot' ) ) . toBeVisible ( { timeout : 15000 } ) ;
186+ await locators . tabs . requestTab ( 'ReqGrpcSnapshot' ) . click ( { force : true } ) ;
187+
188+ await expect ( page2 . getByTestId ( 'responsive-tab-body' ) ) . toHaveAttribute ( 'aria-selected' , 'true' ) ;
189+ await expect ( page2 . locator ( 'text=404 | Not found' ) ) . not . toBeVisible ( ) ;
190+
191+ await closeElectronApp ( app2 ) ;
192+ } ) ;
193+ } ) ;
194+
195+ test ( 'websocket snapshot stores concrete type and body tab key' , async ( { launchElectronApp, createTmpDir } ) => {
196+ const userDataPath = await createTmpDir ( 'snap-ws-snapshot-type-tab-key' ) ;
197+ const colPath = await createTmpDir ( 'col' ) ;
198+
199+ const app = await launchElectronApp ( { userDataPath } ) ;
200+ const page = await app . firstWindow ( ) ;
201+ await page . locator ( '[data-app-state="loaded"]' ) . waitFor ( { timeout : 30000 } ) ;
202+
203+ await test . step ( 'Create collection and WebSocket request' , async ( ) => {
204+ await createCollection ( page , 'TestCol' , colPath ) ;
205+
206+ const locators = buildCommonLocators ( page ) ;
207+ await locators . sidebar . collection ( 'TestCol' ) . hover ( ) ;
208+ await locators . actions . collectionActions ( 'TestCol' ) . click ( ) ;
209+ await locators . dropdown . item ( 'New Request' ) . click ( ) ;
210+
211+ await page . getByTestId ( 'ws-request' ) . click ( ) ;
212+ await page . getByTestId ( 'request-name' ) . fill ( 'ReqWsSnapshot' ) ;
213+ await page . getByTestId ( 'new-request-url' ) . locator ( '.CodeMirror' ) . click ( ) ;
214+ await page . keyboard . type ( 'ws://localhost:8080' ) ;
215+ await locators . modal . button ( 'Create' ) . click ( ) ;
216+
217+ await openRequest ( page , 'TestCol' , 'ReqWsSnapshot' , { persist : true } ) ;
218+ await selectRequestPaneTab ( page , 'Message' ) ;
219+ } ) ;
220+
221+ await test . step ( 'Close app and verify snapshot stores ws-request/body' , async ( ) => {
222+ await page . waitForTimeout ( 2000 ) ;
223+ await closeElectronApp ( app ) ;
224+
225+ const snapshotPath = path . join ( userDataPath , 'ui-state-snapshot.json' ) ;
226+ await expect . poll ( ( ) => fs . existsSync ( snapshotPath ) ) . toBe ( true ) ;
227+
228+ const snapshot = readSnapshot ( userDataPath ) ;
229+ const tab = findSnapshotRequestTab ( snapshot , 'ReqWsSnapshot' ) ;
230+ expect ( tab ) . toBeTruthy ( ) ;
231+ expect ( tab . type ) . toBe ( 'ws-request' ) ;
232+ expect ( tab . request ?. tab ) . toBe ( 'body' ) ;
233+ } ) ;
234+
235+ await test . step ( 'Verify restore opens Message tab and avoids 404' , async ( ) => {
236+ const app2 = await launchElectronApp ( { userDataPath } ) ;
237+ const page2 = await app2 . firstWindow ( ) ;
238+ await page2 . locator ( '[data-app-state="loaded"]' ) . waitFor ( { timeout : 30000 } ) ;
239+
240+ const locators = buildCommonLocators ( page2 ) ;
241+ await expect ( locators . tabs . requestTab ( 'ReqWsSnapshot' ) ) . toBeVisible ( { timeout : 15000 } ) ;
242+ await locators . tabs . requestTab ( 'ReqWsSnapshot' ) . click ( { force : true } ) ;
243+
244+ await expect ( page2 . getByTestId ( 'responsive-tab-body' ) ) . toHaveAttribute ( 'aria-selected' , 'true' ) ;
245+ await expect ( page2 . locator ( 'text=404 | Not found' ) ) . not . toBeVisible ( ) ;
246+
247+ await closeElectronApp ( app2 ) ;
248+ } ) ;
249+ } ) ;
250+
251+ test ( 'graphql snapshot stores concrete type and query tab key' , async ( { launchElectronApp, createTmpDir } ) => {
252+ const userDataPath = await createTmpDir ( 'snap-graphql-snapshot-type-tab-key' ) ;
253+ const colPath = await createTmpDir ( 'col' ) ;
254+
255+ const app = await launchElectronApp ( { userDataPath } ) ;
256+ const page = await app . firstWindow ( ) ;
257+ await page . locator ( '[data-app-state="loaded"]' ) . waitFor ( { timeout : 30000 } ) ;
258+
259+ await test . step ( 'Create collection and GraphQL request' , async ( ) => {
260+ await createCollection ( page , 'TestCol' , colPath ) ;
261+
262+ const locators = buildCommonLocators ( page ) ;
263+ await locators . sidebar . collection ( 'TestCol' ) . hover ( ) ;
264+ await locators . actions . collectionActions ( 'TestCol' ) . click ( ) ;
265+ await locators . dropdown . item ( 'New Request' ) . click ( ) ;
266+
267+ await page . getByTestId ( 'graphql-request' ) . click ( ) ;
268+ await page . getByTestId ( 'request-name' ) . fill ( 'ReqGraphSnapshot' ) ;
269+ await page . getByTestId ( 'new-request-url' ) . locator ( '.CodeMirror' ) . click ( ) ;
270+ await page . keyboard . type ( 'https://echo.usebruno.com/graphql' ) ;
271+ await locators . modal . button ( 'Create' ) . click ( ) ;
272+
273+ await openRequest ( page , 'TestCol' , 'ReqGraphSnapshot' , { persist : true } ) ;
274+ await selectRequestPaneTab ( page , 'Headers' ) ;
275+ } ) ;
276+
277+ await test . step ( 'Close app and verify snapshot stores graphql-request/headers' , async ( ) => {
278+ await page . waitForTimeout ( 2000 ) ;
279+ await closeElectronApp ( app ) ;
280+
281+ const snapshotPath = path . join ( userDataPath , 'ui-state-snapshot.json' ) ;
282+ await expect . poll ( ( ) => fs . existsSync ( snapshotPath ) ) . toBe ( true ) ;
283+
284+ const snapshot = readSnapshot ( userDataPath ) ;
285+ const tab = findSnapshotRequestTab ( snapshot , 'ReqGraphSnapshot' ) ;
286+ expect ( tab ) . toBeTruthy ( ) ;
287+ expect ( tab . type ) . toBe ( 'graphql-request' ) ;
288+ expect ( tab . request ?. tab ) . toBe ( 'headers' ) ;
289+ } ) ;
290+
291+ await test . step ( 'Verify restore opens Headers tab and avoids 404' , async ( ) => {
292+ const app2 = await launchElectronApp ( { userDataPath } ) ;
293+ const page2 = await app2 . firstWindow ( ) ;
294+ await page2 . locator ( '[data-app-state="loaded"]' ) . waitFor ( { timeout : 30000 } ) ;
295+
296+ const locators = buildCommonLocators ( page2 ) ;
297+ await expect ( locators . tabs . requestTab ( 'ReqGraphSnapshot' ) ) . toBeVisible ( { timeout : 15000 } ) ;
298+ await locators . tabs . requestTab ( 'ReqGraphSnapshot' ) . click ( { force : true } ) ;
299+
300+ await expect ( page2 . getByTestId ( 'responsive-tab-headers' ) ) . toHaveAttribute ( 'aria-selected' , 'true' ) ;
301+ await expect ( page2 . locator ( 'text=404 | Not found' ) ) . not . toBeVisible ( ) ;
302+
303+ await closeElectronApp ( app2 ) ;
304+ } ) ;
305+ } ) ;
108306} ) ;
0 commit comments