@@ -44,27 +44,36 @@ describe("validateSandboxParams: v3 cid contract", () => {
4444 }
4545 } ) ;
4646
47- it ( "As the sandbox, I reject a contract that omits the cid" , ( ) => {
48- // Given a contract with no cid param.
47+ it ( "As the sandbox, I reject a contract that omits the cid, but flag it recoverable so the host can re-render me" , ( ) => {
48+ // Given a contract with no cid param (the post-boot strip leaves
49+ // exactly this shape behind, so a reload of a booted sandbox lands here).
4950 const params = search ( { [ SANDBOX_CONTRACT_PARAMS . cid ] : null } ) ;
5051
5152 // When the sandbox validates it.
5253 const result = validateSandboxParams ( params ) ;
5354
54- // Then it fails with a reason that names the missing key.
55+ // Then it fails with a reason that names the missing key, and marks
56+ // the failure recoverable so the boot path asks the host for a fresh
57+ // contract URL instead of dying on a dead-end error page.
5558 expect ( result . ok ) . toBe ( false ) ;
56- if ( ! result . ok ) expect ( result . reason ) . toMatch ( / c i d / i) ;
59+ if ( ! result . ok ) {
60+ expect ( result . reason ) . toMatch ( / c i d / i) ;
61+ expect ( result . recoverable ) . toBe ( true ) ;
62+ }
5763 } ) ;
5864
59- it ( "As the sandbox, I reject a contract whose cid is the empty string" , ( ) => {
65+ it ( "As the sandbox, I reject a contract whose cid is the empty string as fatal, since the host explicitly sent a broken value " , ( ) => {
6066 // Given a contract with an empty cid.
6167 const params = search ( { [ SANDBOX_CONTRACT_PARAMS . cid ] : "" } ) ;
6268
6369 // When the sandbox validates it.
6470 const result = validateSandboxParams ( params ) ;
6571
66- // Then it fails (an empty cid is treated the same as a missing one).
72+ // Then it fails, and is NOT recoverable: an empty value cannot come
73+ // from the post-boot param strip, so re-rendering from the same host
74+ // would produce the same empty cid again.
6775 expect ( result . ok ) . toBe ( false ) ;
76+ if ( ! result . ok ) expect ( result . recoverable ) . not . toBe ( true ) ;
6877 } ) ;
6978
7079 it ( "As the sandbox, I reject a contract whose cid contains non-alphanumeric characters" , ( ) => {
@@ -128,4 +137,20 @@ describe("validateSandboxParams: v3 cid contract", () => {
128137 // Then it fails (network is still required after the v3 bump).
129138 expect ( result . ok ) . toBe ( false ) ;
130139 } ) ;
140+
141+ it ( "As a user whose dApp reloads itself after the param strip, the contract failure is recoverable so the host can restore my session" , ( ) => {
142+ // Given a URL with no contract params at all, which is what a booted
143+ // sandbox window looks like after stripContractParamsFromUrl: a dApp
144+ // calling location.reload() re-enters the boot with this exact shape.
145+ const params = new URLSearchParams ( { theme : "dark" } ) ;
146+
147+ // When the sandbox validates it.
148+ const result = validateSandboxParams ( params ) ;
149+
150+ // Then the failure is recoverable: the host still tracks the rendered
151+ // label and CID, so it can rebuild the iframe instead of stranding the
152+ // user on a full-viewport "Invalid sandbox URL" error.
153+ expect ( result . ok ) . toBe ( false ) ;
154+ if ( ! result . ok ) expect ( result . recoverable ) . toBe ( true ) ;
155+ } ) ;
131156} ) ;
0 commit comments