@@ -41,6 +41,13 @@ class ClientSideSubState(ClientSideState):
41
41
l3 : str = rx .LocalStorage (name = "l3" )
42
42
l4 : str = rx .LocalStorage ("l4 default" )
43
43
44
+ # Sync'd local storage
45
+ l5 : str = rx .LocalStorage (sync = True )
46
+ l6 : str = rx .LocalStorage (sync = True , name = "l6" )
47
+
48
+ def set_l6 (self , my_param : str ):
49
+ self .l6 = my_param
50
+
44
51
def set_var (self ):
45
52
setattr (self , self .state_var , self .input_value )
46
53
self .state_var = self .input_value = ""
@@ -93,6 +100,8 @@ def index():
93
100
rx .box (ClientSideSubState .l2 , id = "l2" ),
94
101
rx .box (ClientSideSubState .l3 , id = "l3" ),
95
102
rx .box (ClientSideSubState .l4 , id = "l4" ),
103
+ rx .box (ClientSideSubState .l5 , id = "l5" ),
104
+ rx .box (ClientSideSubState .l6 , id = "l6" ),
96
105
rx .box (ClientSideSubSubState .c1s , id = "c1s" ),
97
106
rx .box (ClientSideSubSubState .l1s , id = "l1s" ),
98
107
)
@@ -191,33 +200,44 @@ async def test_client_side_state(
191
200
"""
192
201
assert client_side .app_instance is not None
193
202
assert client_side .frontend_url is not None
194
- token_input = driver .find_element (By .ID , "token" )
195
- assert token_input
196
203
197
- # wait for the backend connection to send the token
198
- token = client_side . poll_for_value ( token_input )
199
- assert token is not None
204
+ def poll_for_token ():
205
+ token_input = driver . find_element ( By . ID , "token" )
206
+ assert token_input
200
207
201
- # get a reference to the cookie manipulation form
202
- state_var_input = driver .find_element (By .ID , "state_var" )
203
- input_value_input = driver .find_element (By .ID , "input_value" )
204
- set_sub_state_button = driver .find_element (By .ID , "set_sub_state" )
205
- set_sub_sub_state_button = driver .find_element (By .ID , "set_sub_sub_state" )
208
+ # wait for the backend connection to send the token
209
+ token = client_side .poll_for_value (token_input )
210
+ assert token is not None
211
+ return token
206
212
207
213
def set_sub (var : str , value : str ):
214
+ # Get a reference to the cookie manipulation form.
215
+ state_var_input = driver .find_element (By .ID , "state_var" )
216
+ input_value_input = driver .find_element (By .ID , "input_value" )
217
+ set_sub_state_button = driver .find_element (By .ID , "set_sub_state" )
208
218
AppHarness ._poll_for (lambda : state_var_input .get_attribute ("value" ) == "" )
209
219
AppHarness ._poll_for (lambda : input_value_input .get_attribute ("value" ) == "" )
220
+
221
+ # Set the values.
210
222
state_var_input .send_keys (var )
211
223
input_value_input .send_keys (value )
212
224
set_sub_state_button .click ()
213
225
214
226
def set_sub_sub (var : str , value : str ):
227
+ # Get a reference to the cookie manipulation form.
228
+ state_var_input = driver .find_element (By .ID , "state_var" )
229
+ input_value_input = driver .find_element (By .ID , "input_value" )
230
+ set_sub_sub_state_button = driver .find_element (By .ID , "set_sub_sub_state" )
215
231
AppHarness ._poll_for (lambda : state_var_input .get_attribute ("value" ) == "" )
216
232
AppHarness ._poll_for (lambda : input_value_input .get_attribute ("value" ) == "" )
233
+
234
+ # Set the values.
217
235
state_var_input .send_keys (var )
218
236
input_value_input .send_keys (value )
219
237
set_sub_sub_state_button .click ()
220
238
239
+ token = poll_for_token ()
240
+
221
241
# get a reference to all cookie and local storage elements
222
242
c1 = driver .find_element (By .ID , "c1" )
223
243
c2 = driver .find_element (By .ID , "c2" )
@@ -429,7 +449,7 @@ def set_sub_sub(var: str, value: str):
429
449
assert l1s .text == "l1s value"
430
450
431
451
# reset the backend state to force refresh from client storage
432
- async with client_side .modify_state (token ) as state :
452
+ async with client_side .modify_state (f" { token } _state.client_side_state" ) as state :
433
453
state .reset ()
434
454
driver .refresh ()
435
455
@@ -485,6 +505,31 @@ def set_sub_sub(var: str, value: str):
485
505
"value" : "c5%20value" ,
486
506
}
487
507
508
+ # Open a new tab to check that sync'd local storage is working
509
+ main_tab = driver .window_handles [0 ]
510
+ driver .switch_to .new_window ("window" )
511
+ driver .get (client_side .frontend_url )
512
+
513
+ # New tab should have a different state token.
514
+ assert poll_for_token () != token
515
+
516
+ # Set values and check them in the new tab.
517
+ set_sub ("l5" , "l5 value" )
518
+ set_sub ("l6" , "l6 value" )
519
+ l5 = driver .find_element (By .ID , "l5" )
520
+ l6 = driver .find_element (By .ID , "l6" )
521
+ assert l5 .text == "l5 value"
522
+ assert l6 .text == "l6 value"
523
+
524
+ # Switch back to main window.
525
+ driver .switch_to .window (main_tab )
526
+
527
+ # The values should have updated automatically.
528
+ l5 = driver .find_element (By .ID , "l5" )
529
+ l6 = driver .find_element (By .ID , "l6" )
530
+ assert l5 .text == "l5 value"
531
+ assert l6 .text == "l6 value"
532
+
488
533
# clear the cookie jar and local storage, ensure state reset to default
489
534
driver .delete_all_cookies ()
490
535
local_storage .clear ()
0 commit comments