test_var_operations.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  1. """Integration tests for var operations."""
  2. from typing import Generator
  3. import pytest
  4. from selenium.webdriver.common.by import By
  5. from reflex.testing import AppHarness
  6. def VarOperations():
  7. """App with var operations."""
  8. import reflex as rx
  9. from reflex.vars.base import LiteralVar
  10. from reflex.vars.sequence import ArrayVar
  11. class Object(rx.Base):
  12. name: str = "hello"
  13. class VarOperationState(rx.State):
  14. int_var1: rx.Field[int] = rx.field(10)
  15. int_var2: rx.Field[int] = rx.field(5)
  16. int_var3: rx.Field[int] = rx.field(7)
  17. float_var1: rx.Field[float] = rx.field(10.5)
  18. float_var2: rx.Field[float] = rx.field(5.5)
  19. list1: rx.Field[list] = rx.field([1, 2])
  20. list2: rx.Field[list] = rx.field([3, 4])
  21. list3: rx.Field[list] = rx.field(["first", "second", "third"])
  22. list4: rx.Field[list] = rx.field([Object(name="obj_1"), Object(name="obj_2")])
  23. str_var1: rx.Field[str] = rx.field("first")
  24. str_var2: rx.Field[str] = rx.field("second")
  25. str_var3: rx.Field[str] = rx.field("ThIrD")
  26. str_var4: rx.Field[str] = rx.field("a long string")
  27. dict1: rx.Field[dict[int, int]] = rx.field({1: 2})
  28. dict2: rx.Field[dict[int, int]] = rx.field({3: 4})
  29. html_str: rx.Field[str] = rx.field("<div>hello</div>")
  30. app = rx.App(_state=rx.State)
  31. @rx.memo
  32. def memo_comp(list1: list[int], int_var1: int, id: str):
  33. return rx.text(list1, int_var1, id=id)
  34. @rx.memo
  35. def memo_comp_nested(int_var2: int, id: str):
  36. return memo_comp(list1=[3, 4], int_var1=int_var2, id=id)
  37. @app.add_page
  38. def index():
  39. return rx.vstack(
  40. rx.el.input(
  41. id="token",
  42. value=VarOperationState.router.session.client_token,
  43. is_read_only=True,
  44. ),
  45. # INT INT
  46. rx.text(
  47. VarOperationState.int_var1 + VarOperationState.int_var2,
  48. id="int_add_int",
  49. ),
  50. rx.text(
  51. VarOperationState.int_var1 * VarOperationState.int_var2,
  52. id="int_mult_int",
  53. ),
  54. rx.text(
  55. VarOperationState.int_var1 - VarOperationState.int_var2,
  56. id="int_sub_int",
  57. ),
  58. rx.text(
  59. VarOperationState.int_var1**VarOperationState.int_var2,
  60. id="int_exp_int",
  61. ),
  62. rx.text(
  63. VarOperationState.int_var1 / VarOperationState.int_var2,
  64. id="int_div_int",
  65. ),
  66. rx.text(
  67. VarOperationState.int_var1 // VarOperationState.int_var3,
  68. id="int_floor_int",
  69. ),
  70. rx.text(
  71. VarOperationState.int_var1 % VarOperationState.int_var2,
  72. id="int_mod_int",
  73. ),
  74. rx.text(
  75. VarOperationState.int_var1 | VarOperationState.int_var2,
  76. id="int_or_int",
  77. ),
  78. rx.text(
  79. (VarOperationState.int_var1 > VarOperationState.int_var2).to_string(),
  80. id="int_gt_int",
  81. ),
  82. rx.text(
  83. (VarOperationState.int_var1 < VarOperationState.int_var2).to_string(),
  84. id="int_lt_int",
  85. ),
  86. rx.text(
  87. (VarOperationState.int_var1 >= VarOperationState.int_var2).to_string(),
  88. id="int_gte_int",
  89. ),
  90. rx.text(
  91. (VarOperationState.int_var1 <= VarOperationState.int_var2).to_string(),
  92. id="int_lte_int",
  93. ),
  94. rx.text(
  95. VarOperationState.int_var1 & VarOperationState.int_var2,
  96. id="int_and_int",
  97. ),
  98. rx.text(
  99. (VarOperationState.int_var1 | VarOperationState.int_var2).to_string(),
  100. id="int_or_int",
  101. ),
  102. rx.text(
  103. (VarOperationState.int_var1 == VarOperationState.int_var2).to_string(),
  104. id="int_eq_int",
  105. ),
  106. rx.text(
  107. (VarOperationState.int_var1 != VarOperationState.int_var2).to_string(),
  108. id="int_neq_int",
  109. ),
  110. # INT FLOAT OR FLOAT INT
  111. rx.text(
  112. VarOperationState.float_var1 + VarOperationState.int_var2,
  113. id="float_add_int",
  114. ),
  115. rx.text(
  116. VarOperationState.float_var1 * VarOperationState.int_var2,
  117. id="float_mult_int",
  118. ),
  119. rx.text(
  120. VarOperationState.float_var1 - VarOperationState.int_var2,
  121. id="float_sub_int",
  122. ),
  123. rx.text(
  124. VarOperationState.float_var1**VarOperationState.int_var2,
  125. id="float_exp_int",
  126. ),
  127. rx.text(
  128. VarOperationState.float_var1 / VarOperationState.int_var2,
  129. id="float_div_int",
  130. ),
  131. rx.text(
  132. VarOperationState.float_var1 // VarOperationState.int_var3,
  133. id="float_floor_int",
  134. ),
  135. rx.text(
  136. VarOperationState.float_var1 % VarOperationState.int_var2,
  137. id="float_mod_int",
  138. ),
  139. rx.text(
  140. (VarOperationState.float_var1 > VarOperationState.int_var2).to_string(),
  141. id="float_gt_int",
  142. ),
  143. rx.text(
  144. (VarOperationState.float_var1 < VarOperationState.int_var2).to_string(),
  145. id="float_lt_int",
  146. ),
  147. rx.text(
  148. (
  149. VarOperationState.float_var1 >= VarOperationState.int_var2
  150. ).to_string(),
  151. id="float_gte_int",
  152. ),
  153. rx.text(
  154. (
  155. VarOperationState.float_var1 <= VarOperationState.int_var2
  156. ).to_string(),
  157. id="float_lte_int",
  158. ),
  159. rx.text(
  160. (
  161. VarOperationState.float_var1 == VarOperationState.int_var2
  162. ).to_string(),
  163. id="float_eq_int",
  164. ),
  165. rx.text(
  166. (
  167. VarOperationState.float_var1 != VarOperationState.int_var2
  168. ).to_string(),
  169. id="float_neq_int",
  170. ),
  171. rx.text(
  172. (VarOperationState.float_var1 & VarOperationState.int_var2).to_string(),
  173. id="float_and_int",
  174. ),
  175. rx.text(
  176. (VarOperationState.float_var1 | VarOperationState.int_var2).to_string(),
  177. id="float_or_int",
  178. ),
  179. # INT, DICT
  180. rx.text(
  181. (VarOperationState.int_var1 | VarOperationState.dict1).to_string(),
  182. id="int_or_dict",
  183. ),
  184. rx.text(
  185. (VarOperationState.int_var1 & VarOperationState.dict1).to_string(),
  186. id="int_and_dict",
  187. ),
  188. rx.text(
  189. (VarOperationState.int_var1 == VarOperationState.dict1).to_string(),
  190. id="int_eq_dict",
  191. ),
  192. rx.text(
  193. (VarOperationState.int_var1 != VarOperationState.dict1).to_string(),
  194. id="int_neq_dict",
  195. ),
  196. # FLOAT FLOAT
  197. rx.text(
  198. VarOperationState.float_var1 + VarOperationState.float_var2,
  199. id="float_add_float",
  200. ),
  201. rx.text(
  202. VarOperationState.float_var1 * VarOperationState.float_var2,
  203. id="float_mult_float",
  204. ),
  205. rx.text(
  206. VarOperationState.float_var1 - VarOperationState.float_var2,
  207. id="float_sub_float",
  208. ),
  209. rx.text(
  210. VarOperationState.float_var1**VarOperationState.float_var2,
  211. id="float_exp_float",
  212. ),
  213. rx.text(
  214. VarOperationState.float_var1 / VarOperationState.float_var2,
  215. id="float_div_float",
  216. ),
  217. rx.text(
  218. VarOperationState.float_var1 // VarOperationState.float_var2,
  219. id="float_floor_float",
  220. ),
  221. rx.text(
  222. VarOperationState.float_var1 % VarOperationState.float_var2,
  223. id="float_mod_float",
  224. ),
  225. rx.text(
  226. (
  227. VarOperationState.float_var1 > VarOperationState.float_var2
  228. ).to_string(),
  229. id="float_gt_float",
  230. ),
  231. rx.text(
  232. (
  233. VarOperationState.float_var1 < VarOperationState.float_var2
  234. ).to_string(),
  235. id="float_lt_float",
  236. ),
  237. rx.text(
  238. (
  239. VarOperationState.float_var1 >= VarOperationState.float_var2
  240. ).to_string(),
  241. id="float_gte_float",
  242. ),
  243. rx.text(
  244. (
  245. VarOperationState.float_var1 <= VarOperationState.float_var2
  246. ).to_string(),
  247. id="float_lte_float",
  248. ),
  249. rx.text(
  250. (
  251. VarOperationState.float_var1 == VarOperationState.float_var2
  252. ).to_string(),
  253. id="float_eq_float",
  254. ),
  255. rx.text(
  256. (
  257. VarOperationState.float_var1 != VarOperationState.float_var2
  258. ).to_string(),
  259. id="float_neq_float",
  260. ),
  261. rx.text(
  262. (
  263. VarOperationState.float_var1 & VarOperationState.float_var2
  264. ).to_string(),
  265. id="float_and_float",
  266. ),
  267. rx.text(
  268. (
  269. VarOperationState.float_var1 | VarOperationState.float_var2
  270. ).to_string(),
  271. id="float_or_float",
  272. ),
  273. # FLOAT STR
  274. rx.text(
  275. VarOperationState.float_var1 | VarOperationState.str_var1,
  276. id="float_or_str",
  277. ),
  278. rx.text(
  279. VarOperationState.float_var1 & VarOperationState.str_var1,
  280. id="float_and_str",
  281. ),
  282. rx.text(
  283. (
  284. VarOperationState.float_var1 == VarOperationState.str_var1
  285. ).to_string(),
  286. id="float_eq_str",
  287. ),
  288. rx.text(
  289. (
  290. VarOperationState.float_var1 != VarOperationState.str_var1
  291. ).to_string(),
  292. id="float_neq_str",
  293. ),
  294. # FLOAT LIST
  295. rx.text(
  296. (VarOperationState.float_var1 | VarOperationState.list1).to_string(),
  297. id="float_or_list",
  298. ),
  299. rx.text(
  300. (VarOperationState.float_var1 & VarOperationState.list1).to_string(),
  301. id="float_and_list",
  302. ),
  303. rx.text(
  304. (VarOperationState.float_var1 == VarOperationState.list1).to_string(),
  305. id="float_eq_list",
  306. ),
  307. rx.text(
  308. (VarOperationState.float_var1 != VarOperationState.list1).to_string(),
  309. id="float_neq_list",
  310. ),
  311. # FLOAT DICT
  312. rx.text(
  313. (VarOperationState.float_var1 | VarOperationState.dict1).to_string(),
  314. id="float_or_dict",
  315. ),
  316. rx.text(
  317. (VarOperationState.float_var1 & VarOperationState.dict1).to_string(),
  318. id="float_and_dict",
  319. ),
  320. rx.text(
  321. (VarOperationState.float_var1 == VarOperationState.dict1).to_string(),
  322. id="float_eq_dict",
  323. ),
  324. rx.text(
  325. (VarOperationState.float_var1 != VarOperationState.dict1).to_string(),
  326. id="float_neq_dict",
  327. ),
  328. # STR STR
  329. rx.text(
  330. VarOperationState.str_var1 + VarOperationState.str_var2,
  331. id="str_add_str",
  332. ),
  333. rx.text(
  334. (VarOperationState.str_var1 > VarOperationState.str_var2).to_string(),
  335. id="str_gt_str",
  336. ),
  337. rx.text(
  338. (VarOperationState.str_var1 < VarOperationState.str_var2).to_string(),
  339. id="str_lt_str",
  340. ),
  341. rx.text(
  342. (VarOperationState.str_var1 >= VarOperationState.str_var2).to_string(),
  343. id="str_gte_str",
  344. ),
  345. rx.text(
  346. (VarOperationState.str_var1 <= VarOperationState.str_var2).to_string(),
  347. id="str_lte_str",
  348. ),
  349. rx.text(
  350. (
  351. VarOperationState.float_var1 == VarOperationState.float_var2
  352. ).to_string(),
  353. id="str_eq_str",
  354. ),
  355. rx.text(
  356. (
  357. VarOperationState.float_var1 != VarOperationState.float_var2
  358. ).to_string(),
  359. id="str_neq_str",
  360. ),
  361. rx.text(
  362. VarOperationState.str_var1.contains("fir").to_string(),
  363. id="str_contains",
  364. ),
  365. rx.text(
  366. VarOperationState.str_var1 | VarOperationState.str_var1,
  367. id="str_or_str",
  368. ),
  369. rx.text(
  370. VarOperationState.str_var1 & VarOperationState.str_var2,
  371. id="str_and_str",
  372. ),
  373. # STR, INT
  374. rx.text(
  375. VarOperationState.str_var1 * VarOperationState.int_var2,
  376. id="str_mult_int",
  377. ),
  378. rx.text(
  379. VarOperationState.str_var1 & VarOperationState.int_var2,
  380. id="str_and_int",
  381. ),
  382. rx.text(
  383. VarOperationState.str_var1 | VarOperationState.int_var2,
  384. id="str_or_int",
  385. ),
  386. rx.text(
  387. (VarOperationState.str_var1 == VarOperationState.int_var1).to_string(),
  388. id="str_eq_int",
  389. ),
  390. rx.text(
  391. (VarOperationState.str_var1 != VarOperationState.int_var1).to_string(),
  392. id="str_neq_int",
  393. ),
  394. # STR, LIST
  395. rx.text(
  396. VarOperationState.str_var1 | VarOperationState.list1,
  397. id="str_or_list",
  398. ),
  399. rx.text(
  400. (VarOperationState.str_var1 & VarOperationState.list1).to_string(),
  401. id="str_and_list",
  402. ),
  403. rx.text(
  404. (VarOperationState.str_var1 == VarOperationState.list1).to_string(),
  405. id="str_eq_list",
  406. ),
  407. rx.text(
  408. (VarOperationState.str_var1 != VarOperationState.list1).to_string(),
  409. id="str_neq_list",
  410. ),
  411. # STR, DICT
  412. rx.text(
  413. VarOperationState.str_var1 | VarOperationState.dict1,
  414. id="str_or_dict",
  415. ),
  416. rx.text(
  417. (VarOperationState.str_var1 & VarOperationState.dict1).to_string(),
  418. id="str_and_dict",
  419. ),
  420. rx.text(
  421. (VarOperationState.str_var1 == VarOperationState.dict1).to_string(),
  422. id="str_eq_dict",
  423. ),
  424. rx.text(
  425. (VarOperationState.str_var1 != VarOperationState.dict1).to_string(),
  426. id="str_neq_dict",
  427. ),
  428. # LIST, LIST
  429. rx.text(
  430. (VarOperationState.list1 + VarOperationState.list2).to_string(),
  431. id="list_add_list",
  432. ),
  433. rx.text(
  434. (VarOperationState.list1 & VarOperationState.list2).to_string(),
  435. id="list_and_list",
  436. ),
  437. rx.text(
  438. (VarOperationState.list1 | VarOperationState.list2).to_string(),
  439. id="list_or_list",
  440. ),
  441. rx.text(
  442. (VarOperationState.list1 > VarOperationState.list2).to_string(),
  443. id="list_gt_list",
  444. ),
  445. rx.text(
  446. (VarOperationState.list1 < VarOperationState.list2).to_string(),
  447. id="list_lt_list",
  448. ),
  449. rx.text(
  450. (VarOperationState.list1 >= VarOperationState.list2).to_string(),
  451. id="list_gte_list",
  452. ),
  453. rx.text(
  454. (VarOperationState.list1 <= VarOperationState.list2).to_string(),
  455. id="list_lte_list",
  456. ),
  457. rx.text(
  458. (VarOperationState.list1 == VarOperationState.list2).to_string(),
  459. id="list_eq_list",
  460. ),
  461. rx.text(
  462. (VarOperationState.list1 != VarOperationState.list2).to_string(),
  463. id="list_neq_list",
  464. ),
  465. rx.text(
  466. VarOperationState.list1.contains(1).to_string(),
  467. id="list_contains",
  468. ),
  469. rx.text(VarOperationState.list4.pluck("name").to_string(), id="list_pluck"),
  470. rx.text(VarOperationState.list1.reverse().to_string(), id="list_reverse"),
  471. # LIST, INT
  472. rx.text(
  473. (VarOperationState.list1 * VarOperationState.int_var2).to_string(),
  474. id="list_mult_int",
  475. ),
  476. rx.text(
  477. (VarOperationState.list1 | VarOperationState.int_var1).to_string(),
  478. id="list_or_int",
  479. ),
  480. rx.text(
  481. (VarOperationState.list1 & VarOperationState.int_var1).to_string(),
  482. id="list_and_int",
  483. ),
  484. rx.text(
  485. (VarOperationState.list1 == VarOperationState.int_var1).to_string(),
  486. id="list_eq_int",
  487. ),
  488. rx.text(
  489. (VarOperationState.list1 != VarOperationState.int_var1).to_string(),
  490. id="list_neq_int",
  491. ),
  492. # LIST, DICT
  493. rx.text(
  494. (VarOperationState.list1 | VarOperationState.dict1).to_string(),
  495. id="list_or_dict",
  496. ),
  497. rx.text(
  498. (VarOperationState.list1 & VarOperationState.dict1).to_string(),
  499. id="list_and_dict",
  500. ),
  501. rx.text(
  502. (VarOperationState.list1 == VarOperationState.dict1).to_string(),
  503. id="list_eq_dict",
  504. ),
  505. rx.text(
  506. (VarOperationState.list1 != VarOperationState.dict1).to_string(),
  507. id="list_neq_dict",
  508. ),
  509. # DICT, DICT
  510. rx.text(
  511. (VarOperationState.dict1 | VarOperationState.dict2).to_string(),
  512. id="dict_or_dict",
  513. ),
  514. rx.text(
  515. (VarOperationState.dict1 & VarOperationState.dict2).to_string(),
  516. id="dict_and_dict",
  517. ),
  518. rx.text(
  519. (VarOperationState.dict1 == VarOperationState.dict2).to_string(),
  520. id="dict_eq_dict",
  521. ),
  522. rx.text(
  523. (VarOperationState.dict1 != VarOperationState.dict2).to_string(),
  524. id="dict_neq_dict",
  525. ),
  526. rx.text(
  527. VarOperationState.dict1.contains(1).to_string(),
  528. id="dict_contains",
  529. ),
  530. rx.text(VarOperationState.str_var3.lower(), id="str_lower"),
  531. rx.text(VarOperationState.str_var3.upper(), id="str_upper"),
  532. rx.text(VarOperationState.str_var4.split(" ").to_string(), id="str_split"),
  533. rx.text(VarOperationState.list3.join(""), id="list_join"),
  534. rx.text(VarOperationState.list3.join(","), id="list_join_comma"),
  535. # Index from an op var
  536. rx.text(
  537. VarOperationState.list3[VarOperationState.int_var1 % 3],
  538. id="list_index_mod",
  539. ),
  540. rx.html(
  541. VarOperationState.html_str,
  542. id="html_str",
  543. ),
  544. rx.el.mark("second"),
  545. rx.text(ArrayVar.range(2, 5).join(","), id="list_join_range1"),
  546. rx.text(ArrayVar.range(2, 10, 2).join(","), id="list_join_range2"),
  547. rx.text(ArrayVar.range(5, 0, -1).join(","), id="list_join_range3"),
  548. rx.text(ArrayVar.range(0, 3).join(","), id="list_join_range4"),
  549. rx.box(
  550. rx.foreach(
  551. ArrayVar.range(0, 2),
  552. lambda x: rx.text(VarOperationState.list1[x], as_="p"),
  553. ),
  554. id="foreach_list_arg",
  555. ),
  556. rx.box(
  557. rx.foreach(
  558. ArrayVar.range(0, 2),
  559. lambda x, ix: rx.text(VarOperationState.list1[ix], as_="p"),
  560. ),
  561. id="foreach_list_ix",
  562. ),
  563. rx.box(
  564. rx.foreach(
  565. LiteralVar.create(list(range(0, 3))).to(ArrayVar, list[int]),
  566. lambda x: rx.foreach(
  567. ArrayVar.range(x),
  568. lambda y: rx.text(VarOperationState.list1[y], as_="p"),
  569. ),
  570. ),
  571. id="foreach_list_nested",
  572. ),
  573. memo_comp(
  574. list1=VarOperationState.list1,
  575. int_var1=VarOperationState.int_var1,
  576. id="memo_comp",
  577. ),
  578. memo_comp_nested(
  579. int_var2=VarOperationState.int_var2,
  580. id="memo_comp_nested",
  581. ),
  582. # foreach in a match
  583. rx.box(
  584. rx.match(
  585. VarOperationState.list3.length(),
  586. (0, rx.text("No choices")),
  587. (1, rx.text("One choice")),
  588. rx.foreach(VarOperationState.list3, lambda choice: rx.text(choice)),
  589. ),
  590. id="foreach_in_match",
  591. ),
  592. # Literal range var in a foreach
  593. rx.box(rx.foreach(range(42, 80, 27), rx.text.span), id="range_in_foreach1"),
  594. rx.box(rx.foreach(range(42, 80, 3), rx.text.span), id="range_in_foreach2"),
  595. rx.box(rx.foreach(range(42, 20, -6), rx.text.span), id="range_in_foreach3"),
  596. rx.box(rx.foreach(range(42, 43, 5), rx.text.span), id="range_in_foreach4"),
  597. )
  598. @pytest.fixture(scope="module")
  599. def var_operations(tmp_path_factory) -> Generator[AppHarness, None, None]:
  600. """Start VarOperations app at tmp_path via AppHarness.
  601. Args:
  602. tmp_path_factory: pytest tmp_path_factory fixture
  603. Yields:
  604. running AppHarness instance
  605. """
  606. with AppHarness.create(
  607. root=tmp_path_factory.mktemp("var_operations"),
  608. app_source=VarOperations,
  609. ) as harness:
  610. assert harness.app_instance is not None, "app is not running"
  611. yield harness
  612. @pytest.fixture
  613. def driver(var_operations: AppHarness):
  614. """Get an instance of the browser open to the var operations app.
  615. Args:
  616. var_operations: harness for VarOperations app
  617. Yields:
  618. WebDriver instance.
  619. """
  620. driver = var_operations.frontend()
  621. try:
  622. token_input = driver.find_element(By.ID, "token")
  623. assert token_input
  624. # wait for the backend connection to send the token
  625. token = var_operations.poll_for_value(token_input)
  626. assert token is not None
  627. yield driver
  628. finally:
  629. driver.quit()
  630. def test_var_operations(driver, var_operations: AppHarness):
  631. """Test that the var operations produce the right results.
  632. Args:
  633. driver: selenium WebDriver open to the app
  634. var_operations: AppHarness for the var operations app
  635. """
  636. tests = [
  637. # int, int
  638. ("int_add_int", "15"),
  639. ("int_mult_int", "50"),
  640. ("int_sub_int", "5"),
  641. ("int_exp_int", "100000"),
  642. ("int_div_int", "2"),
  643. ("int_floor_int", "1"),
  644. ("int_mod_int", "0"),
  645. ("int_gt_int", "true"),
  646. ("int_lt_int", "false"),
  647. ("int_gte_int", "true"),
  648. ("int_lte_int", "false"),
  649. ("int_and_int", "5"),
  650. ("int_or_int", "10"),
  651. ("int_eq_int", "false"),
  652. ("int_neq_int", "true"),
  653. # int, float
  654. ("float_add_int", "15.5"),
  655. ("float_mult_int", "52.5"),
  656. ("float_sub_int", "5.5"),
  657. ("float_exp_int", "127628.15625"),
  658. ("float_div_int", "2.1"),
  659. ("float_floor_int", "1"),
  660. ("float_mod_int", "0.5"),
  661. ("float_gt_int", "true"),
  662. ("float_lt_int", "false"),
  663. ("float_gte_int", "true"),
  664. ("float_lte_int", "false"),
  665. ("float_eq_int", "false"),
  666. ("float_neq_int", "true"),
  667. ("float_and_int", "5"),
  668. ("float_or_int", "10.5"),
  669. # int, dict
  670. ("int_or_dict", "10"),
  671. ("int_and_dict", '{"1":2}'),
  672. ("int_eq_dict", "false"),
  673. ("int_neq_dict", "true"),
  674. # float, float
  675. ("float_add_float", "16"),
  676. ("float_mult_float", "57.75"),
  677. ("float_sub_float", "5"),
  678. ("float_exp_float", "413562.49323606625"),
  679. ("float_div_float", "1.9090909090909092"),
  680. ("float_floor_float", "1"),
  681. ("float_mod_float", "5"),
  682. ("float_gt_float", "true"),
  683. ("float_lt_float", "false"),
  684. ("float_gte_float", "true"),
  685. ("float_lte_float", "false"),
  686. ("float_eq_float", "false"),
  687. ("float_neq_float", "true"),
  688. ("float_and_float", "5.5"),
  689. ("float_or_float", "10.5"),
  690. # float, str
  691. ("float_or_str", "10.5"),
  692. ("float_and_str", "first"),
  693. ("float_eq_str", "false"),
  694. ("float_neq_str", "true"),
  695. # float, list
  696. ("float_or_list", "10.5"),
  697. ("float_and_list", "[1,2]"),
  698. ("float_eq_list", "false"),
  699. ("float_neq_list", "true"),
  700. # float, dict
  701. ("float_or_dict", "10.5"),
  702. ("float_and_dict", '{"1":2}'),
  703. ("float_eq_dict", "false"),
  704. ("float_neq_dict", "true"),
  705. # str, str
  706. ("str_add_str", "firstsecond"),
  707. ("str_gt_str", "false"),
  708. ("str_lt_str", "true"),
  709. ("str_gte_str", "false"),
  710. ("str_lte_str", "true"),
  711. ("str_eq_str", "false"),
  712. ("str_neq_str", "true"),
  713. ("str_and_str", "second"),
  714. ("str_or_str", "first"),
  715. ("str_contains", "true"),
  716. ("str_lower", "third"),
  717. ("str_upper", "THIRD"),
  718. ("str_split", '["a","long","string"]'),
  719. # str, int
  720. ("str_mult_int", "firstfirstfirstfirstfirst"),
  721. ("str_and_int", "5"),
  722. ("str_or_int", "first"),
  723. ("str_eq_int", "false"),
  724. ("str_neq_int", "true"),
  725. # str, list
  726. ("str_and_list", "[1,2]"),
  727. ("str_or_list", "first"),
  728. ("str_eq_list", "false"),
  729. ("str_neq_list", "true"),
  730. # str, dict
  731. ("str_or_dict", "first"),
  732. ("str_and_dict", '{"1":2}'),
  733. ("str_eq_dict", "false"),
  734. ("str_neq_dict", "true"),
  735. # list, list
  736. ("list_add_list", "[1,2,3,4]"),
  737. ("list_gt_list", "false"),
  738. ("list_lt_list", "true"),
  739. ("list_gte_list", "false"),
  740. ("list_lte_list", "true"),
  741. ("list_eq_list", "false"),
  742. ("list_neq_list", "true"),
  743. ("list_and_list", "[3,4]"),
  744. ("list_or_list", "[1,2]"),
  745. ("list_contains", "true"),
  746. ("list_pluck", '["obj_1","obj_2"]'),
  747. ("list_reverse", "[2,1]"),
  748. ("list_join", "firstsecondthird"),
  749. ("list_join_comma", "first,second,third"),
  750. ("list_join_range1", "2,3,4"),
  751. ("list_join_range2", "2,4,6,8"),
  752. ("list_join_range3", "5,4,3,2,1"),
  753. ("list_join_range4", "0,1,2"),
  754. # list, int
  755. ("list_mult_int", "[1,2,1,2,1,2,1,2,1,2]"),
  756. ("list_or_int", "[1,2]"),
  757. ("list_and_int", "10"),
  758. ("list_eq_int", "false"),
  759. ("list_neq_int", "true"),
  760. # list, dict
  761. ("list_and_dict", '{"1":2}'),
  762. ("list_or_dict", "[1,2]"),
  763. ("list_eq_dict", "false"),
  764. ("list_neq_dict", "true"),
  765. # dict, dict
  766. ("dict_or_dict", '{"1":2}'),
  767. ("dict_and_dict", '{"3":4}'),
  768. ("dict_eq_dict", "false"),
  769. ("dict_neq_dict", "true"),
  770. ("dict_contains", "true"),
  771. # index from an op var
  772. ("list_index_mod", "second"),
  773. # html component with var
  774. ("html_str", "hello"),
  775. # index into list with foreach
  776. ("foreach_list_arg", "1\n2"),
  777. ("foreach_list_ix", "1\n2"),
  778. ("foreach_list_nested", "1\n1\n2"),
  779. # rx.memo component with state
  780. ("memo_comp", "1210"),
  781. ("memo_comp_nested", "345"),
  782. # foreach in a match
  783. ("foreach_in_match", "first\nsecond\nthird"),
  784. # literal range in a foreach
  785. ("range_in_foreach1", "4269"),
  786. ("range_in_foreach2", "42454851545760636669727578"),
  787. ("range_in_foreach3", "42363024"),
  788. ("range_in_foreach4", "42"),
  789. ]
  790. for tag, expected in tests:
  791. print(tag)
  792. assert driver.find_element(By.ID, tag).text == expected
  793. # Highlight component with var query (does not plumb ID)
  794. assert driver.find_element(By.TAG_NAME, "mark").text == "second"