@@ -31,75 +31,100 @@ beforeEach(() => {
3131} ) ;
3232
3333describe ( 'buildSessionsIndex' , ( ) => {
34- it ( 'returns "No sessions recorded." when empty' , ( ) => {
35- expect ( buildSessionsIndex ( ) ) . toBe ( 'No sessions recorded.' ) ;
34+ it ( 'returns valid JSON with empty sessions array when no sessions' , ( ) => {
35+ const parsed = JSON . parse ( buildSessionsIndex ( ) ) ;
36+ expect ( parsed . sessions ) . toEqual ( [ ] ) ;
3637 } ) ;
3738
38- it ( 'lists all sessions with id, type, step count ' , ( ) => {
39+ it ( 'lists all sessions with id, type, stepCount ' , ( ) => {
3940 addHistory ( 'abc-1' , 'browser' , false , true ) ;
4041 addHistory ( 'def-2' , 'ios' ) ;
41- const result = buildSessionsIndex ( ) ;
42- expect ( result ) . toContain ( 'abc-1' ) ;
43- expect ( result ) . toContain ( 'def-2' ) ;
44- expect ( result ) . toContain ( 'browser ' ) ;
45- expect ( result ) . toContain ( 'ios ' ) ;
42+ const parsed = JSON . parse ( buildSessionsIndex ( ) ) ;
43+ expect ( parsed . sessions ) . toHaveLength ( 2 ) ;
44+ const ids = parsed . sessions . map ( ( s : any ) => s . sessionId ) ;
45+ expect ( ids ) . toContain ( 'abc-1 ' ) ;
46+ expect ( ids ) . toContain ( 'def-2 ' ) ;
4647 } ) ;
4748
48- it ( 'marks current session with [current] ' , ( ) => {
49+ it ( 'marks the current session with isCurrent: true ' , ( ) => {
4950 addHistory ( 'cur-1' , 'browser' , true ) ;
5051 addHistory ( 'old-1' , 'browser' , false , true ) ;
51- const result = buildSessionsIndex ( ) ;
52- expect ( result ) . toContain ( '[current]' ) ;
53- // only the current one should be marked
54- const lines = result . split ( '\n' ) . filter ( ( l ) => l . includes ( '[current]' ) ) ;
55- expect ( lines ) . toHaveLength ( 1 ) ;
56- expect ( lines [ 0 ] ) . toContain ( 'cur-1' ) ;
52+ const parsed = JSON . parse ( buildSessionsIndex ( ) ) ;
53+ const current = parsed . sessions . filter ( ( s : any ) => s . isCurrent ) ;
54+ expect ( current ) . toHaveLength ( 1 ) ;
55+ expect ( current [ 0 ] . sessionId ) . toBe ( 'cur-1' ) ;
5756 } ) ;
5857
59- it ( 'shows step count per session' , ( ) => {
58+ it ( 'includes stepCount per session' , ( ) => {
6059 const h = addHistory ( 'sess-steps' , 'browser' ) ;
6160 h . steps . push ( { index : 1 , tool : 'navigate' , params : { } , status : 'ok' , durationMs : 10 , timestamp : '' } ) ;
6261 h . steps . push ( { index : 2 , tool : 'click_element' , params : { } , status : 'ok' , durationMs : 5 , timestamp : '' } ) ;
63- const result = buildSessionsIndex ( ) ;
64- expect ( result ) . toContain ( '2 steps' ) ;
62+ const parsed = JSON . parse ( buildSessionsIndex ( ) ) ;
63+ expect ( parsed . sessions [ 0 ] . stepCount ) . toBe ( 2 ) ;
6564 } ) ;
6665} ) ;
6766
6867describe ( 'buildCurrentSessionSteps' , ( ) => {
69- it ( 'returns "No active session." when no current session' , ( ) => {
70- expect ( buildCurrentSessionSteps ( ) ) . toBe ( 'No active session.' ) ;
68+ it ( 'returns null when no current session' , ( ) => {
69+ expect ( buildCurrentSessionSteps ( ) ) . toBeNull ( ) ;
7170 } ) ;
7271
73- it ( 'returns step listing and generated JS for current session' , ( ) => {
72+ it ( 'returns stepsJson and generatedJs for the current session' , ( ) => {
7473 const h = addHistory ( 'live-1' , 'browser' , true ) ;
7574 h . steps . push ( { index : 1 , tool : 'navigate' , params : { url : 'https://x.com' } , status : 'ok' , durationMs : 50 , timestamp : '2026-01-01T00:00:00.000Z' } ) ;
7675 const result = buildCurrentSessionSteps ( ) ;
77- expect ( result ) . toContain ( 'live-1' ) ;
78- expect ( result ) . toContain ( 'navigate' ) ;
79- expect ( result ) . toContain ( 'Generated WebdriverIO JS' ) ;
80- expect ( result ) . toContain ( "await browser.url('https://x.com');" ) ;
76+ expect ( result ) . not . toBeNull ( ) ;
77+ expect ( result ! . stepsJson ) . toBeDefined ( ) ;
78+ expect ( result ! . generatedJs ) . toBeDefined ( ) ;
8179 } ) ;
8280} ) ;
8381
8482describe ( 'buildSessionStepsById' , ( ) => {
85- it ( 'returns "Session not found" for unknown sessionId' , ( ) => {
86- expect ( buildSessionStepsById ( 'nonexistent' ) ) . toBe ( 'Session not found: nonexistent' ) ;
83+ it ( 'returns null for unknown sessionId' , ( ) => {
84+ expect ( buildSessionStepsById ( 'nonexistent' ) ) . toBeNull ( ) ;
8785 } ) ;
8886
89- it ( 'returns session steps for known sessionId ' , ( ) => {
87+ it ( 'stepsJson is valid JSON with session metadata and steps array ' , ( ) => {
9088 const h = addHistory ( 'hist-1' , 'ios' ) ;
9189 h . steps . push ( { index : 1 , tool : 'tap_element' , params : { selector : '~btn' } , status : 'ok' , durationMs : 20 , timestamp : '2026-01-01T00:00:00.000Z' } ) ;
9290 const result = buildSessionStepsById ( 'hist-1' ) ;
93- expect ( result ) . toContain ( 'hist-1' ) ;
94- expect ( result ) . toContain ( 'tap_element' ) ;
95- expect ( result ) . toContain ( 'Generated WebdriverIO JS' ) ;
91+ expect ( result ) . not . toBeNull ( ) ;
92+ const parsed = JSON . parse ( result ! . stepsJson ) ;
93+ expect ( parsed . sessionId ) . toBe ( 'hist-1' ) ;
94+ expect ( parsed . type ) . toBe ( 'ios' ) ;
95+ expect ( parsed . startedAt ) . toBe ( '2026-01-01T00:00:00.000Z' ) ;
96+ expect ( parsed . stepCount ) . toBe ( 1 ) ;
97+ expect ( Array . isArray ( parsed . steps ) ) . toBe ( true ) ;
98+ expect ( parsed . steps [ 0 ] ) . toMatchObject ( {
99+ index : 1 ,
100+ tool : 'tap_element' ,
101+ params : { selector : '~btn' } ,
102+ status : 'ok' ,
103+ durationMs : 20 ,
104+ } ) ;
96105 } ) ;
97106
98- it ( 'marks error steps with [error] in the step list' , ( ) => {
107+ it ( 'generatedJs contains valid WebdriverIO code' , ( ) => {
108+ const h = addHistory ( 'hist-2' , 'browser' ) ;
109+ h . steps . push ( { index : 1 , tool : 'navigate' , params : { url : 'https://example.com' } , status : 'ok' , durationMs : 10 , timestamp : '2026-01-01T00:00:00.000Z' } ) ;
110+ const result = buildSessionStepsById ( 'hist-2' ) ;
111+ expect ( result ! . generatedJs ) . toContain ( "await browser.url('https://example.com');" ) ;
112+ expect ( result ! . generatedJs ) . toContain ( "import { remote } from 'webdriverio';" ) ;
113+ } ) ;
114+
115+ it ( 'error steps appear in stepsJson with status and error fields' , ( ) => {
99116 const h = addHistory ( 'err-1' , 'browser' ) ;
100117 h . steps . push ( { index : 1 , tool : 'click_element' , params : { selector : '#x' } , status : 'error' , error : 'Not found' , durationMs : 5 , timestamp : '2026-01-01T00:00:00.000Z' } ) ;
101118 const result = buildSessionStepsById ( 'err-1' ) ;
102- expect ( result ) . toContain ( '[error]' ) ;
103- expect ( result ) . toContain ( 'Not found' ) ;
119+ const parsed = JSON . parse ( result ! . stepsJson ) ;
120+ expect ( parsed . steps [ 0 ] . status ) . toBe ( 'error' ) ;
121+ expect ( parsed . steps [ 0 ] . error ) . toBe ( 'Not found' ) ;
122+ } ) ;
123+
124+ it ( 'stepsJson includes endedAt when session has ended' , ( ) => {
125+ addHistory ( 'ended-1' , 'browser' , false , true ) ;
126+ const result = buildSessionStepsById ( 'ended-1' ) ;
127+ const parsed = JSON . parse ( result ! . stepsJson ) ;
128+ expect ( parsed . endedAt ) . toBe ( '2026-01-01T01:00:00.000Z' ) ;
104129 } ) ;
105130} ) ;
0 commit comments