selenium-selenium-4.23.0/0000775000175000017500000000000014647614150015132 5ustar carstencarstenselenium-selenium-4.23.0/requirements_lock.txt0000664000175000017500000011140114646203155021422 0ustar carstencarsten# # This file is autogenerated by pip-compile with Python 3.8 # by the following command: # # bazel run //py:requirements.update # async-generator==1.10 \ --hash=sha256:01c7bf666359b4967d2cda0000cc2e4af16a0ae098cbffcb8472fb9e8ad6585b \ --hash=sha256:6ebb3d106c12920aaae42ccb6f787ef5eefdcdd166ea3d628fa8476abe712144 # via # -r py/requirements.txt # trio # trio-websocket attrs==23.2.0 \ --hash=sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30 \ --hash=sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1 # via # -r py/requirements.txt # outcome # trio certifi==2023.11.17 \ --hash=sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1 \ --hash=sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474 # via # -r py/requirements.txt # requests cffi==1.16.0 \ --hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \ --hash=sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a \ --hash=sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417 \ --hash=sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab \ --hash=sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520 \ --hash=sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36 \ --hash=sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743 \ --hash=sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8 \ --hash=sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed \ --hash=sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684 \ --hash=sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56 \ --hash=sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324 \ --hash=sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d \ --hash=sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235 \ --hash=sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e \ --hash=sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088 \ --hash=sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000 \ --hash=sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7 \ --hash=sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e \ --hash=sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673 \ --hash=sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c \ --hash=sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe \ --hash=sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2 \ --hash=sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098 \ --hash=sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8 \ --hash=sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a \ --hash=sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0 \ --hash=sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b \ --hash=sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896 \ --hash=sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e \ --hash=sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9 \ --hash=sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2 \ --hash=sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b \ --hash=sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6 \ --hash=sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404 \ --hash=sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f \ --hash=sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0 \ --hash=sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4 \ --hash=sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc \ --hash=sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936 \ --hash=sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba \ --hash=sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872 \ --hash=sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb \ --hash=sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614 \ --hash=sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1 \ --hash=sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d \ --hash=sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969 \ --hash=sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b \ --hash=sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4 \ --hash=sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627 \ --hash=sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956 \ --hash=sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357 # via # -r py/requirements.txt # cryptography charset-normalizer==3.3.2 \ --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \ --hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \ --hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \ --hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \ --hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \ --hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \ --hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \ --hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \ --hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \ --hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \ --hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \ --hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \ --hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \ --hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \ --hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \ --hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \ --hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \ --hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \ --hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \ --hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \ --hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \ --hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \ --hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \ --hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \ --hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \ --hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \ --hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \ --hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \ --hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \ --hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \ --hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \ --hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \ --hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \ --hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \ --hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \ --hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \ --hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \ --hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \ --hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \ --hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \ --hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \ --hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \ --hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \ --hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \ --hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \ --hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \ --hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \ --hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \ --hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \ --hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \ --hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \ --hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \ --hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \ --hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \ --hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \ --hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \ --hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \ --hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \ --hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \ --hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \ --hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \ --hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \ --hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \ --hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \ --hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \ --hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \ --hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \ --hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \ --hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \ --hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \ --hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \ --hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \ --hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \ --hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \ --hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \ --hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \ --hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \ --hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \ --hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \ --hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \ --hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \ --hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \ --hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \ --hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \ --hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \ --hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \ --hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \ --hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \ --hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \ --hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561 # via requests cryptography==42.0.7 \ --hash=sha256:02c0eee2d7133bdbbc5e24441258d5d2244beb31da5ed19fbb80315f4bbbff55 \ --hash=sha256:0d563795db98b4cd57742a78a288cdbdc9daedac29f2239793071fe114f13785 \ --hash=sha256:16268d46086bb8ad5bf0a2b5544d8a9ed87a0e33f5e77dd3c3301e63d941a83b \ --hash=sha256:1a58839984d9cb34c855197043eaae2c187d930ca6d644612843b4fe8513c886 \ --hash=sha256:2954fccea107026512b15afb4aa664a5640cd0af630e2ee3962f2602693f0c82 \ --hash=sha256:2e47577f9b18723fa294b0ea9a17d5e53a227867a0a4904a1a076d1646d45ca1 \ --hash=sha256:31adb7d06fe4383226c3e963471f6837742889b3c4caa55aac20ad951bc8ffda \ --hash=sha256:3577d029bc3f4827dd5bf8bf7710cac13527b470bbf1820a3f394adb38ed7d5f \ --hash=sha256:36017400817987670037fbb0324d71489b6ead6231c9604f8fc1f7d008087c68 \ --hash=sha256:362e7197754c231797ec45ee081f3088a27a47c6c01eff2ac83f60f85a50fe60 \ --hash=sha256:3de9a45d3b2b7d8088c3fbf1ed4395dfeff79d07842217b38df14ef09ce1d8d7 \ --hash=sha256:4f698edacf9c9e0371112792558d2f705b5645076cc0aaae02f816a0171770fd \ --hash=sha256:5482e789294854c28237bba77c4c83be698be740e31a3ae5e879ee5444166582 \ --hash=sha256:5e44507bf8d14b36b8389b226665d597bc0f18ea035d75b4e53c7b1ea84583cc \ --hash=sha256:779245e13b9a6638df14641d029add5dc17edbef6ec915688f3acb9e720a5858 \ --hash=sha256:789caea816c6704f63f6241a519bfa347f72fbd67ba28d04636b7c6b7da94b0b \ --hash=sha256:7f8b25fa616d8b846aef64b15c606bb0828dbc35faf90566eb139aa9cff67af2 \ --hash=sha256:8cb8ce7c3347fcf9446f201dc30e2d5a3c898d009126010cbd1f443f28b52678 \ --hash=sha256:93a3209f6bb2b33e725ed08ee0991b92976dfdcf4e8b38646540674fc7508e13 \ --hash=sha256:a3a5ac8b56fe37f3125e5b72b61dcde43283e5370827f5233893d461b7360cd4 \ --hash=sha256:a47787a5e3649008a1102d3df55424e86606c9bae6fb77ac59afe06d234605f8 \ --hash=sha256:a79165431551042cc9d1d90e6145d5d0d3ab0f2d66326c201d9b0e7f5bf43604 \ --hash=sha256:a987f840718078212fdf4504d0fd4c6effe34a7e4740378e59d47696e8dfb477 \ --hash=sha256:a9bc127cdc4ecf87a5ea22a2556cab6c7eda2923f84e4f3cc588e8470ce4e42e \ --hash=sha256:bd13b5e9b543532453de08bcdc3cc7cebec6f9883e886fd20a92f26940fd3e7a \ --hash=sha256:c65f96dad14f8528a447414125e1fc8feb2ad5a272b8f68477abbcc1ea7d94b9 \ --hash=sha256:d8e3098721b84392ee45af2dd554c947c32cc52f862b6a3ae982dbb90f577f14 \ --hash=sha256:e6b79d0adb01aae87e8a44c2b64bc3f3fe59515280e00fb6d57a7267a2583cda \ --hash=sha256:e6b8f1881dac458c34778d0a424ae5769de30544fc678eac51c1c8bb2183e9da \ --hash=sha256:e9b2a6309f14c0497f348d08a065d52f3020656f675819fc405fb63bbcd26562 \ --hash=sha256:ecbfbc00bf55888edda9868a4cf927205de8499e7fabe6c050322298382953f2 \ --hash=sha256:efd0bf5205240182e0f13bcaea41be4fdf5c22c5129fc7ced4a0282ac86998c9 # via # -r py/requirements.txt # pyopenssl # secretstorage debugpy==1.8.1 \ --hash=sha256:016a9fcfc2c6b57f939673c874310d8581d51a0fe0858e7fac4e240c5eb743cb \ --hash=sha256:0de56aba8249c28a300bdb0672a9b94785074eb82eb672db66c8144fff673146 \ --hash=sha256:1a9fe0829c2b854757b4fd0a338d93bc17249a3bf69ecf765c61d4c522bb92a8 \ --hash=sha256:28acbe2241222b87e255260c76741e1fbf04fdc3b6d094fcf57b6c6f75ce1242 \ --hash=sha256:3a79c6f62adef994b2dbe9fc2cc9cc3864a23575b6e387339ab739873bea53d0 \ --hash=sha256:3bda0f1e943d386cc7a0e71bfa59f4137909e2ed947fb3946c506e113000f741 \ --hash=sha256:3ebb70ba1a6524d19fa7bb122f44b74170c447d5746a503e36adc244a20ac539 \ --hash=sha256:58911e8521ca0c785ac7a0539f1e77e0ce2df753f786188f382229278b4cdf23 \ --hash=sha256:6df9aa9599eb05ca179fb0b810282255202a66835c6efb1d112d21ecb830ddd3 \ --hash=sha256:7a3afa222f6fd3d9dfecd52729bc2e12c93e22a7491405a0ecbf9e1d32d45b39 \ --hash=sha256:7eb7bd2b56ea3bedb009616d9e2f64aab8fc7000d481faec3cd26c98a964bcdd \ --hash=sha256:92116039b5500633cc8d44ecc187abe2dfa9b90f7a82bbf81d079fcdd506bae9 \ --hash=sha256:a2e658a9630f27534e63922ebf655a6ab60c370f4d2fc5c02a5b19baf4410ace \ --hash=sha256:bfb20cb57486c8e4793d41996652e5a6a885b4d9175dd369045dad59eaacea42 \ --hash=sha256:caad2846e21188797a1f17fc09c31b84c7c3c23baf2516fed5b40b378515bbf0 \ --hash=sha256:d915a18f0597ef685e88bb35e5d7ab968964b7befefe1aaea1eb5b2640b586c7 \ --hash=sha256:dda73bf69ea479c8577a0448f8c707691152e6c4de7f0c4dec5a4bc11dee516e \ --hash=sha256:e38beb7992b5afd9d5244e96ad5fa9135e94993b0c551ceebf3fe1a5d9beb234 \ --hash=sha256:edcc9f58ec0fd121a25bc950d4578df47428d72e1a0d66c07403b04eb93bcf98 \ --hash=sha256:efd3fdd3f67a7e576dd869c184c5dd71d9aaa36ded271939da352880c012e703 \ --hash=sha256:f696d6be15be87aef621917585f9bb94b1dc9e8aced570db1b8a6fc14e8f9b42 \ --hash=sha256:fd97ed11a4c7f6d042d320ce03d83b20c3fb40da892f994bc041bbc415d7a099 # via -r py/requirements.txt docutils==0.20.1 \ --hash=sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6 \ --hash=sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b # via readme-renderer exceptiongroup==1.1.1 \ --hash=sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e \ --hash=sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785 # via # pytest # trio h11==0.14.0 \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 # via # -r py/requirements.txt # wsproto idna==3.7 \ --hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \ --hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0 # via # -r py/requirements.txt # requests # trio importlib-metadata==6.8.0 \ --hash=sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb \ --hash=sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743 # via # -r py/requirements.txt # keyring # twine importlib-resources==6.1.1 \ --hash=sha256:3893a00122eafde6894c59914446a512f728a0c1a45f9bb9b63721b6bacf0b4a \ --hash=sha256:e8bf90d8213b486f428c9c39714b920041cb02c184686a3dee24905aaa8105d6 # via keyring inflection==0.5.1 \ --hash=sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417 \ --hash=sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2 # via -r py/requirements.txt iniconfig==2.0.0 \ --hash=sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3 \ --hash=sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374 # via # -r py/requirements.txt # pytest jaraco-classes==3.3.0 \ --hash=sha256:10afa92b6743f25c0cf5f37c6bb6e18e2c5bb84a16527ccfc0040ea377e7aaeb \ --hash=sha256:c063dd08e89217cee02c8d5e5ec560f2c8ce6cdc2fcdc2e68f7b2e5547ed3621 # via keyring jeepney==0.8.0 \ --hash=sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806 \ --hash=sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755 # via # keyring # secretstorage keyring==24.3.0 \ --hash=sha256:4446d35d636e6a10b8bce7caa66913dd9eca5fd222ca03a3d42c38608ac30836 \ --hash=sha256:e730ecffd309658a08ee82535a3b5ec4b4c8669a9be11efb66249d8e0aeb9a25 # via twine markdown-it-py==3.0.0 \ --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \ --hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb # via rich mdurl==0.1.2 \ --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba # via markdown-it-py more-itertools==10.1.0 \ --hash=sha256:626c369fa0eb37bac0291bce8259b332fd59ac792fa5497b59837309cd5b114a \ --hash=sha256:64e0735fcfdc6f3464ea133afe8ea4483b1c5fe3a3d69852e6503b43a0b222e6 # via # -r py/requirements.txt # jaraco-classes multidict==6.0.5 \ --hash=sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556 \ --hash=sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c \ --hash=sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29 \ --hash=sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b \ --hash=sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8 \ --hash=sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7 \ --hash=sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd \ --hash=sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40 \ --hash=sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6 \ --hash=sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3 \ --hash=sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c \ --hash=sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9 \ --hash=sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5 \ --hash=sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae \ --hash=sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442 \ --hash=sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9 \ --hash=sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc \ --hash=sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c \ --hash=sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea \ --hash=sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5 \ --hash=sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50 \ --hash=sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182 \ --hash=sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453 \ --hash=sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e \ --hash=sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600 \ --hash=sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733 \ --hash=sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda \ --hash=sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241 \ --hash=sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461 \ --hash=sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e \ --hash=sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e \ --hash=sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b \ --hash=sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e \ --hash=sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7 \ --hash=sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386 \ --hash=sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd \ --hash=sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9 \ --hash=sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf \ --hash=sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee \ --hash=sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5 \ --hash=sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a \ --hash=sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271 \ --hash=sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54 \ --hash=sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4 \ --hash=sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496 \ --hash=sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb \ --hash=sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319 \ --hash=sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3 \ --hash=sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f \ --hash=sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527 \ --hash=sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed \ --hash=sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604 \ --hash=sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef \ --hash=sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8 \ --hash=sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5 \ --hash=sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5 \ --hash=sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626 \ --hash=sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c \ --hash=sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d \ --hash=sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c \ --hash=sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc \ --hash=sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc \ --hash=sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b \ --hash=sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38 \ --hash=sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450 \ --hash=sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1 \ --hash=sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f \ --hash=sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3 \ --hash=sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755 \ --hash=sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226 \ --hash=sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a \ --hash=sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046 \ --hash=sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf \ --hash=sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479 \ --hash=sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e \ --hash=sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1 \ --hash=sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a \ --hash=sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83 \ --hash=sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929 \ --hash=sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93 \ --hash=sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a \ --hash=sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c \ --hash=sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44 \ --hash=sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89 \ --hash=sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba \ --hash=sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e \ --hash=sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da \ --hash=sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24 \ --hash=sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423 \ --hash=sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef # via -r py/requirements.txt nh3==0.2.15 \ --hash=sha256:0d02d0ff79dfd8208ed25a39c12cbda092388fff7f1662466e27d97ad011b770 \ --hash=sha256:3277481293b868b2715907310c7be0f1b9d10491d5adf9fce11756a97e97eddf \ --hash=sha256:3b803a5875e7234907f7d64777dfde2b93db992376f3d6d7af7f3bc347deb305 \ --hash=sha256:427fecbb1031db085eaac9931362adf4a796428ef0163070c484b5a768e71601 \ --hash=sha256:5f0d77272ce6d34db6c87b4f894f037d55183d9518f948bba236fe81e2bb4e28 \ --hash=sha256:60684857cfa8fdbb74daa867e5cad3f0c9789415aba660614fe16cd66cbb9ec7 \ --hash=sha256:6f42f99f0cf6312e470b6c09e04da31f9abaadcd3eb591d7d1a88ea931dca7f3 \ --hash=sha256:86e447a63ca0b16318deb62498db4f76fc60699ce0a1231262880b38b6cff911 \ --hash=sha256:8d595df02413aa38586c24811237e95937ef18304e108b7e92c890a06793e3bf \ --hash=sha256:9c0d415f6b7f2338f93035bba5c0d8c1b464e538bfbb1d598acd47d7969284f0 \ --hash=sha256:a5167a6403d19c515217b6bcaaa9be420974a6ac30e0da9e84d4fc67a5d474c5 \ --hash=sha256:ac19c0d68cd42ecd7ead91a3a032fdfff23d29302dbb1311e641a130dfefba97 \ --hash=sha256:b1e97221cedaf15a54f5243f2c5894bb12ca951ae4ddfd02a9d4ea9df9e1a29d \ --hash=sha256:bc2d086fb540d0fa52ce35afaded4ea526b8fc4d3339f783db55c95de40ef02e \ --hash=sha256:d1e30ff2d8d58fb2a14961f7aac1bbb1c51f9bdd7da727be35c63826060b0bf3 \ --hash=sha256:f3b53ba93bb7725acab1e030bc2ecd012a817040fd7851b332f86e2f9bb98dc6 # via readme-renderer outcome==1.3.0 \ --hash=sha256:588ef4dc10b64e8df160d8d1310c44e1927129a66d6d2ef86845cef512c5f24c \ --hash=sha256:7b688fd82db72f4b0bc9e883a00359d4d4179cd97d27f09c9644d0c842ba7786 # via # -r py/requirements.txt # pytest-trio # trio packaging==23.2 \ --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7 # via # -r py/requirements.txt # pytest pkginfo==1.9.6 \ --hash=sha256:4b7a555a6d5a22169fcc9cf7bfd78d296b0361adad412a346c1226849af5e546 \ --hash=sha256:8fd5896e8718a4372f0ea9cc9d96f6417c9b986e23a4d116dda26b62cc29d046 # via twine pluggy==1.3.0 \ --hash=sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12 \ --hash=sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7 # via # -r py/requirements.txt # pytest py==1.11.0 \ --hash=sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719 \ --hash=sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378 # via -r py/requirements.txt pycparser==2.21 \ --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 # via # -r py/requirements.txt # cffi pygments==2.17.2 \ --hash=sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c \ --hash=sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367 # via # readme-renderer # rich pyopenssl==22.0.0 \ --hash=sha256:660b1b1425aac4a1bea1d94168a85d99f0b3144c869dd4390d27629d0087f1bf \ --hash=sha256:ea252b38c87425b64116f808355e8da644ef9b07e429398bfece610f893ee2e0 # via -r py/requirements.txt pyparsing==3.1.2 \ --hash=sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad \ --hash=sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742 # via -r py/requirements.txt pysocks==1.7.1 \ --hash=sha256:08e69f092cc6dbe92a0fdd16eeb9b9ffbc13cadfe5ca4c7bd92ffb078b293299 \ --hash=sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5 \ --hash=sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0 # via # -r py/requirements.txt # urllib3 pytest==7.4.4 \ --hash=sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280 \ --hash=sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8 # via # -r py/requirements.txt # pytest-instafail # pytest-mock # pytest-trio pytest-instafail==0.5.0 \ --hash=sha256:33a606f7e0c8e646dc3bfee0d5e3a4b7b78ef7c36168cfa1f3d93af7ca706c9e \ --hash=sha256:6855414487e9e4bb76a118ce952c3c27d3866af15487506c4ded92eb72387819 # via -r py/requirements.txt pytest-mock==3.12.0 \ --hash=sha256:0972719a7263072da3a21c7f4773069bcc7486027d7e8e1f81d98a47e701bc4f \ --hash=sha256:31a40f038c22cad32287bb43932054451ff5583ff094bca6f675df2f8bc1a6e9 # via -r py/requirements.txt pytest-trio==0.8.0 \ --hash=sha256:8363db6336a79e6c53375a2123a41ddbeccc4aa93f93788651641789a56fb52e \ --hash=sha256:e6a7e7351ae3e8ec3f4564d30ee77d1ec66e1df611226e5618dbb32f9545c841 # via -r py/requirements.txt readme-renderer==42.0 \ --hash=sha256:13d039515c1f24de668e2c93f2e877b9dbe6c6c32328b90a40a49d8b2b85f36d \ --hash=sha256:2d55489f83be4992fe4454939d1a051c33edbab778e82761d060c9fc6b308cd1 # via twine requests==2.31.0 \ --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \ --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1 # via # requests-toolbelt # twine requests-toolbelt==1.0.0 \ --hash=sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6 \ --hash=sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06 # via twine rfc3986==2.0.0 \ --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd \ --hash=sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c # via twine rich==13.7.0 \ --hash=sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa \ --hash=sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235 # via twine secretstorage==3.3.3 \ --hash=sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77 \ --hash=sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99 # via keyring sniffio==1.3.1 \ --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \ --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc # via # -r py/requirements.txt # trio sortedcontainers==2.4.0 \ --hash=sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88 \ --hash=sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0 # via # -r py/requirements.txt # trio toml==0.10.2 \ --hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b \ --hash=sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f # via -r py/requirements.txt tomli==2.0.1 \ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f # via pytest trio==0.22.0 \ --hash=sha256:ce68f1c5400a47b137c5a4de72c7c901bd4e7a24fbdebfe9b41de8c6c04eaacf \ --hash=sha256:f1dd0780a89bfc880c7c7994519cb53f62aacb2c25ff487001c0052bd721cdf0 # via # -r py/requirements.txt # pytest-trio # trio-websocket trio-websocket==0.9.2 \ --hash=sha256:5b558f6e83cc20a37c3b61202476c5295d1addf57bd65543364e0337e37ed2bc \ --hash=sha256:a3d34de8fac26023eee701ed1e7bf4da9a8326b61a62934ec9e53b64970fd8fe # via -r py/requirements.txt twine==4.0.2 \ --hash=sha256:929bc3c280033347a00f847236564d1c52a3e61b1ac2516c97c48f3ceab756d8 \ --hash=sha256:9e102ef5fdd5a20661eb88fad46338806c3bd32cf1db729603fe3697b1bc83c8 # via -r py/requirements.txt typing-extensions==4.9.0 \ --hash=sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783 \ --hash=sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd # via # -r py/requirements.txt # rich urllib3[socks]==2.0.7 \ --hash=sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84 \ --hash=sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e # via # -r py/requirements.txt # requests # twine websocket-client==1.8.0 \ --hash=sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526 \ --hash=sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da # via -r py/requirements.txt wsproto==1.2.0 \ --hash=sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065 \ --hash=sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736 # via # -r py/requirements.txt # trio-websocket zipp==3.17.0 \ --hash=sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31 \ --hash=sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0 # via # -r py/requirements.txt # importlib-metadata # importlib-resources selenium-selenium-4.23.0/LICENSE0000664000175000017500000002614514646203155016145 0ustar carstencarsten Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2024 Software Freedom Conservancy (SFC) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. selenium-selenium-4.23.0/pnpm-workspace.yaml0000664000175000017500000000011414646203155020756 0ustar carstencarstenpackages: - 'javascript/grid-ui' - 'javascript/node/selenium-webdriver' selenium-selenium-4.23.0/CHANGES0000664000175000017500000015557314646203155016143 0ustar carstencarstenSelenium 4.23.0 * Disable strict time stamps in Firefox profile (#14168) * Update the py api doc build (#14173) * Add websocket-client v.1.8.0 to setup.py (#14187) * Remove precompiled binaries from sdist (#14233) * Fix RelativeBy#near to take 2 parameters (#13082) * Add CDP for Chrome 127 and remove 124 Selenium 4.22.0 * Fix EOFError when calling the Remote WebDriver download_file method (#14031) * Add low-level sync API to use DevTools (#13977) * Add preference to enable CDP in Firefox by default (#14091) * Allow using enable_bidi property on options class * Implement script module for BiDi * Remove desired capabilities argument for Webkitgtk (#14128) * Make webkitgtk.webdriver same as wpewebkit.webdriver * Add CDP for Chrome 126 and remove 123 Selenium 4.21.0 * Add CDP for Chrome 125 and remove 122 * Moving ignore_local_proxy_environment_variables to BaseOptions (#13926) Selenium 4.20.0 * Add CDP for Chrome 124 and remove 121 * Add type hints for selenium.webdriver.remote.webdriver.WebDriver.__init__ (#13775) * Add types to set_window_position parameters (#13786) * Making Selenium Manager a thin wrapper (#13387) * This change has been made to make it easier to maintain and improve, the interface has changed and if users were invoking it, they might experience issues. Selenium Manager is still in beta and these type of changes are expected. Selenium 4.19.0 * Add CDP for Chrome 123 and remove 120 * Add more network interfaces to detect lan ip (#13663) * install_addon() didn't take into account dir paths with trailing slashes (#13694) * Explicitly export Select and WebDriverWait from selenium.webdriver.support.ui (#13491) * Add return type to webelement.submit (#13490) * Add type to parameter of webelement.WebElement.send_keys (#13492) Selenium 4.18.1 * Add CDP for Chrome 122 and remove 119 Selenium 4.18.0 * Update linting dependencies * Setting Python for nightly releases - https://test.pypi.org/project/selenium/ Selenium 4.17.2 * [py] Correct typing_extension dependency for wheel generation Selenium 4.17.1 * Fix typo in setup.py (#13487) Selenium 4.17.0 * Add page load strategy enum (#13258) * Use correct file name when bumping versions (#13282) * Filter which bidi logs are recorded based on event type (#12951) * Add python to Selenium Manager input for tracking (see #13288) * Sleep depending on the number of attempts to check if the service has started (#13321) * Use subprocess.DEVNULL instead of open(os.devnull) to avoid leaking a file handle (#13329) * Remove all references to firefox-bin * Check if architecture/platform combination is supported for Selenium Manager (#13381) * Remove extension connection class and other usages of webdriver.xpi * remove deprecated verbose argument from edge service * remove deprecated desired_capabilities property from webdriver * remove deprecated application cache support * truncate large strings when logging requests * Update WPEWebKit support code (#13278) * [py] Fix WPEWebKit python support code * Do not change profile preferences of an existing directory by default (#13477) * Deprecate firefox profile methods that are not supported (#13477) * deprecate FirefoxBinary class (#13476) * Fix type error in mypy (#13482) * Add CDP for Chrome 121 and remove 118 Selenium 4.16.0 * Fix inadvertent code change in mutation_event * Fix bug in using SE_MANAGER_PATH * Fix bug where downloaded file was not getting unzipped * Add more logging to driver startup * Fix WebDriverWait type hints for WebElement (#13108) * Clean up of usage of executable path in services * Don't leak a file descriptor to os.devnull by default (#13162) * Allow bsd operating systems to use the linux binary * Close trio memory channel sender after the driver is quit (#13151) * Remote webdriver cannot match Chromium browser name for remote connection * Remove deprecated reuse_service parameter from Safari driver constructor * Remove deprecated quiet parameter from Safari service constructor * Ensure all drivers stop service during driver quit * Update chromium driver constructors for readability * Add CDP for Chrome 120 and remove 117 Selenium 4.15.2 * Fix bug for unzipping downloaded files Selenium 4.15.1 * Fix bug in using SE_MANAGER_PATH * Fix inadvertent code change in mutation_event Selenium 4.15.0 * Return a `pathlib.Path` when `SE_MANAGER_PATH` is set. closes #12929 * Do not set browser binary in selenium manager if it is an empty string (#12738) * Add CDP v119 and remove v116 * Remove selenium manager accommodation for Conda * Implement file downloads (#12979) * Add some type hints to selenium.webdriver.support (#13070) Selenium 4.14.0 * add CDP files for v118 and remove v115 * use lazy string interpolation for logging calls * Fix dangling log_output in Service (#12871) Selenium 4.13.0 * add CDP files for v117 and remove v114 * do not send parameters in payload that are used in endpoint (#12685) * close out driver logging on quit (#12637) * disable console appearing on windows when running in pythonw (#12715) * remove deprecated headless methods * fix bug preventing using performance logging in chromium * remove deprecation notice from Firefox profiles * Allow users to set Selenium Manager path by environment variable (#12752) Selenium 4.12.0 * Add CDP files for v116 and remove v113 * fix bug in ElementScrollBehavior in IE Options (#12462) * fix bug preventing sending keys with long strings (#12474) * fix typing for action_chains (#12477) * fix typing for IE Options (#12464) * fix bug in common options (#12499) * allow setting http client certifications with REQUESTS_CA_BUNDLE env (#11957) * support conda installation of selenium manager (#12536) * Drop support for `python3.7` * Fixed a bug where `Popen.wait()` calls caught the wrong exceptions when timing out Selenium 4.11.2 * better bug fix for #12454 Selenium 4.11.1 * Delete unusable Safari Options parameters to fix bug preventing Safari execution (#12454) Selenium 4.11.0 * Add CDP files for v115 and remove v112 * removed redundant attributes `capabilities` and `set_capability` in wpewebkit/options.py (#12169) * mapped all error codes in `errorhandler.py` to corresponding exception object. (#12190) * improve driver logging (#12103) - implement log_output() for flexibility and consistency of driver logging * fix property name in Selenium Manager (#12237) * used truthy check instead of checking for length in `to_capabilities` method in `ie/options.py` (#12262) * remote commands dict is moved outside `RemoteConnection` class in `remote/remote_connection.py` (#12261) * moved `ConnectionType` class outside `Mobile` class to avoid nesting of classes (#12256) * used `pathlib` module to check if the file exist in `remote/file_detector.py` (#12253) * added truthy check in chromium options instead of identity operator (#12274) * added pythonic approach of type checking in `firefox/firefox_profile.py` (#12271) * let users pass service args to IE driver (#12272) * Adding ignore process match for IE Mode across bindings (#12279) * moved all ie options to custom descriptors. (#12283) * minor ie-options fix to PR 12283 (#12309), fixes #12283 * added type hints to `SwitchTo` class (#12296) * Refactored Proxy object in common/proxy.py using custom descriptor. (#12286) * optimized Timeouts class by moving timeouts to descriptor class (#12287) * added type hinting support to ActionChains and Alert class (#12290) * Moved all `PrintOptions` class attributes to custom descriptor class. (#12297) * Use Selenium Manager to locate drivers on PATH (#12356 * Enable cdp to work for edge * Update docstring of wait.py so it can also cover the case of WebElement as 1st arg of WebDriverWait. (#12376) * Added type hinting support to `common/actions` libraries. (#12325) * Fix type of `ignore_proxy` in `ChromiumRemoteconnection` * set exception direct cause when switching frame focus when NSE is raised * Raise a more generic `ValueError` when proxy type is not acceptable * Add browser output from selenium manager to options (#12404) * Add check=False explicitly to subprocess calls; simplify `keys_to_typing` * Expose `WPEWebKitService` and `WebKitGTKService` in the public API * Remove deprecated `ActionChains.scroll(...)` * Removed unused variable `DEFAULT_SAFARI_CAPS` in `safari/webdriver.py` (#12416) * Added type checks in `setter` methods of different browser options (#12328) * Add creation flag for windows in selenium_manager (#12435) * Fix checking window handles for current Selenium 4.10.0 * Add CDP files for v114 and remove v111 * Fix bug preventing proxy from working in Options classes (#12029) * Add proxy support for Selenium Manager (#12032) * Additional updates to typing (#12067, #12106) * Add support for changing pointers in Actions class (#11521) * Remove browser filters for shadow root element searches (#12112) * Remove significant amounts of deprecated code (#12030) * Improve near relative locator behavior (#11290) * Change Selenium Manager logging to debug (#12145) * Add links to documentation in error messages (#12156) * Add custom error class for driver location and improve error logic * Fix bug in BiDi mutation events Selenium 4.9.1 * Add CDP files for v113 and remove v110 * Minor fixes for docstring and dictionary declarations (#11975) * Update logging to match other bindings (#11990) * Support newer versions of urllib3 (#11993) Selenium 4.9.0 * Remove "shadow_root" assertion in Python bindings for Firefox (#11821) * Simplify driver binary and driver location selecting (#11864) * Do not pass desired caps in Safari (#11854) * Selenium Manager get Browser Version from Options classes * Selenium Manager use binary from Browser Options * Adding v112 and removing v109 Selenium 4.8.3 * Add fine grained control for arguments provided to service subprocesses by passing a `popen_kw` mapping for all services. * `Options` classes now allow `timeout` to be set partially and no longer raise an exception when all values are not provided. (#11623) * No longer sending `SIGKILL` to subprocesses in instances where `SIGTERM` was successful within 60 seconds. * Add CDP files for v111 and remove v108 * Pass default to `pop` when parsing service popen_kw * Using json output with Selenium Manager * Sphinx config update to keep invoked methods and shorter aliases in documentation (#11802) Selenium 4.8.2 * Update tox.ini for a valid "isort" version (#11667) * Undo a bug fix that caused a worse bug. (#11666) Selenium 4.8.1 * Add CDP files for v110 and remove v107 * pylint fixes including tidy of f strings, simplifications of conditional statements and isinstances (#11205) * Replace devtools genrule with proper generate_devtools rule. (#11392) * Add docstring for `alert_is_present` * Updating Selenium Manager binaries for 4.8.1 release Selenium 4.8.0 * Add CDP files for v109 and remove v106 * Add logging to Selenium Manager for both stdout and stderr * Multiple updates and improvements to types * Fix sdist tar package_dir (#11416) * Add comment with name of large JS executions (#11038) * Deprecate headless property for chromium and firefox options classes (#11467) Selenium 4.7.2 * Put selenium manager bug fix from 4.7.1 in the correct place Selenium 4.7.1 * Fix bug preventing selenium manager from using Internet Explorer Selenium 4.7.0 * Add CDP files for v108 and remove v105 * Improve error handling with Selenium Manager (#11329) * Fix bug preventing alternate package managers from using Selenium Manager (#11234) Selenium 4.6.1 * Replace response.getheader() with response.headers.get() (deprecated in urllib3 1.26.13). * Fixed a bug in `Service` destructors accessing modules that no longer existed during interpreter shutdown. * Improved exception messages when raising for `relative` locator issues. Selenium 4.6.0 * Document firefox `service=` arg. closes #11067 * Additional types and tidying safari service * Revert removal of default executable global for safari * Additional types; remove unused `permissions.py` * Remove `RemoteDriverServerException` * Remove unused `send_remote_shutdown_command` implementations in services * Update `log_path` docs for non chromium based services * Make `get_screenshot_as_file()` work with pathlib.Paths (#11095) * Remove `protocols.py` * fix typing in get_full_page_screenshot_as_png (#11163) * typo in error message (#11166) * Adding CDP files for v107 and removing v104 * add initial support for selenium manager * Revert "[py] do not allow Select class to work with disabled selects" * #11093 - The SessionId shouldn't be added to params themself bu… (#11121) Selenium 4.5.0 * Fix frame_to_be_available_and_switch_to_it() for string inputs (#10963) * Implicit non w3c capability conversion for `acceptSslCerts`, `platform` and `version` is now deprecated * Additional type hints * Bugfix options returning `None` when strict_file_interactability, set_window_rect or accept_insecure_certs are not set * Add CDP for v105, remove support for v102 * Add CDP for v106, remove support for v103 Selenium 4.4.3 * Update explicit dependency for certifi to remove upper bound (#10956) Selenium 4.4.2 * Add explicit dependency for certifi (#10953) Selenium 4.4.1 * Removal of urllib3[secure] extras (deprecated) dependency Selenium 4.4.0 * More flexibility in locating Firefox binary (#10818) * Add CDP for v104, remove support for v101 * Throw error when setting w3c to False on Chromium, and warning when setting w3c to True Selenium 4.3.0 * Deprecated find_element_by_* and find_elements_by_* are now removed (#10712) * Deprecated Opera support has been removed (#10630) * Fully upgraded from python 2x to 3.7 syntax and features (#10647) * Added a devtools version fallback mechanism to look for an older version when mismatch occurs (#10749) * Better support for co-operative multi inheritance by utilising super() throughout * Improved type hints throughout Selenium 4.2.0 * Fix bug preventing Firefox from setting accept_insecure_certs to False (#10442) * Deprecated opera classes as not w3c compatible (#10379) * Fix SecurityError: Invalid Domain problem (#10653) * Implement convenience methods for scrolling Selenium 4.1.5 * use `typing_extensions` to be compatible with `py37` (#10613) Selenium 4.1.4 * Hook options class in safari driver (#10433) * Remove universal wheel, python 2 is unsupported (#10438) * Fix `tox -e docs` by pinning `Jinja2` (#10492) * Add support Chrome 100 and remove for Chrome 97 * Removed desired capabilities from handshake code (#10494) * Invalid selector exceptions are is not a no such element exception * Do not convert tag name to css selector * Add debug logging for urllib response data (#10568) * Use monotonic clock for waits, fixes #10544 (#10550) * Adding Chrome DevTools 101 and removing 98 * Add the ability to create sdist package of the python bindings * Remove unicode prefix for strings (#10562) * Use `get_timeout()` for urllib pool manager timeouts in remote connection (#10563) * Fixing "--connect-existing" #10598 * Added DeprecationWarning to the warnings.warn methods inside the find_element_by_x methods (#10575) * Added virtual authenticator for Python Bindings (#10579) Selenium 4.1.3 * fix generated wheel asset (#10022) * add support for proxy authentication (#10358) * add Safari options (#10385) * add support for Firefox to install unpacked addons (#10308) * add support for Chrome 99 and remove support for Chrome 96 Selenium 4.1.2 * Include `py.typed` in the library Selenium 4.1.1 * add support for Chrome 98 and remove support for Chrome 95 * Add py.typed file (#10310) * Elaborate find_element deprecation message (#10273) * add support for Chrome v97 * convert selectors for finding elements in shadow dom * missing self for service args * don't use websocket-port if user sets connect-existing (a4dc6e) * update tests for current IE options * fix firefox addon tests * Support new Cast command added to Chrome Devtools (#10150) * send Base64 encoded addon to driver instead of path String * Reflect how find_elements returns a list, not just one WebElement. (#10172) * add shadowroot to api docs * add log reference to api rst file * remove non breaking space for doc generation * Updating exceptions file for docs * Add type hinting to Shadowroot * update ShadowRoot find element signatures to match those in WebElement (#10138) * add Zenkaku/Hankaku key * raise `NoSuchElementException` for relative failures instead of `IndexError` (#10078) * Remove legacy in favour of W3C endpoints. (#10075) * Tidy relativeby docs, use non deprecated methods in webserver (#10077, #10103, #10108, #10186, #10212, #10120) * PEP 484 type hints s (#10099) * Handle Socks Proxy for Remote Connections. Fixes #10091 * Add extra attributes to pointer down and pointer move actions * Add Scroll via Wheel Inputs and Wheel Actions Selenium 4.1.0 * add warning if people set w3c to false as it may break their tests * Fix wrong type annotations for "env" it's a dict not a string (#10072) * Added default executable path in service module for (#10057) * Fix typos for docstrings (#10052) * Fix return type hint in get_screenshot_as_png (#10060) * Add CDP for v96, remove support for v92 and v93 * Add support for shadow dom end points * Upgrade sphinx to use latest * Correct docstrings around Service usage * XFail alert tests due to https://bugzilla.mozilla.org/show_bug.cgi\?id\=1731795 * Remove py2 import code * Check the values in NO_PROXY and set the poolmanager accordingly (#9925, #9967) * Move python version to a variable to be shared about in build steps * Bump Bazel rules_pkg to 0.5.1 Selenium 4.0.0 * Add cdp 95 to python and JS * Remove Edge legacy options. (#9908) * Expected condition for checking attribute value (#9881) * implement relative locator for find_element (#9902) * Fix python generation code for CDP to optionals better Selenium 4 Release Candidate 3 * Fix CDP Code Generation broken by Chromium 94 * Fix Deprecation warnings for IE Bindings. Fixes #9818 Selenium 4 Release Candidate 2 * Add new websocketUrl capability * Force free ports for cdp in geckodriver * Add w3c capabilities to Python options (#9870) * expected_conditions and wait modules raises InvalidSelectorException for invalid xpaths (#9805) * implement chromium specific endpoint for setting permissions * implement chromium specific endpoint for deleting network conditions * update ruby, python and JS to add support for v94 and remove support for v92 * Fix type hint on chrome option method (#9840) * Allows None to be set for the sameSite attribute (#9771) * Fix typo in python webdriver for IE (#9801) Selenium 4 Release Candidate 1 * Remove cdp versions 88, 89, and 90 * Replace v91 with v93 in bazel files * update IE options class in each language to match the currently supported capabilities in the IE Driver * Specify that the "find_element_by_* ..." warning is a deprecation warning (#9700) * clean up imports * Use options when passing things to remote webdriver instead of capabilities (#9678) * Correct deprecation message in IE handling code * Rewrite the logging module for bidi connections * remove non-w3c compliant parameters from default capabilities * Run type checks in CI and report typing coverage to codecov (#9523) * PEP 484 Type Hints added * Handle first/always match better when it hits lists/dicts. Fixes #9538 * correct tox warnings * Fix deprecation warnings for Safari (#9577) * Allow 0 coordinates for the window position. Fixes #9574 * Fix incorrect use of 'NoReturn' type annotation. (#9540) Selenium 4 Beta 4 (The Final Beta) * Returning fixed IP in GitHub actions (#9550) * PEP 484 type hints for common.exceptions and webdriver.support.color (#9482) * Add the ability to pass in multiple options and have that capabilities returned as (first|always)Match * Add docstrings for RelativeBy * Add the ability to pass in different locators to do Relative Locator searches * Add a test with returning a JS Const object #9468 * Handle poor responses from drivers when there are errors. Fixes #9437 * Add the ability to enable mobile on options classes * Add the ability to use Options classes on Safari * Fix converting list of tuples to str in send_keys (#9330) * Expand element to be clickable in expected conditions(#9374) * Upgrade rules_python to 0.2.0 Selenium 4 Beta 3 * Enable more tests * Improve support for WebDriver Bidi over selenium grid * Update CDP Support versions to remove 86,87 and add 90,91 * Allow overriding the default 250 msecs duration of pointer movement (#9336) * Only give deprecation warning if Profile is being used in options * Loosen version requirements on dependencies. Fixes #9312 * Bump urllib3 from 1.26.2 to 1.26.3 in /py (#9311) * Disable wait on frame test due to bug in Firefox * Correct pinned browser path for chrome on linux Selenium 4 beta 2 Post 1 * Fix Chrome instantiation Selenium 4 beta 2 * Set up python for pinned browsers * Add Multiple file upload test * Fix using arguments in Chrome Option. Fixes #9281 * Deprecate arguments in remote webdriver instantiation * Improve proxy via options test for Firefox * Set Chromium Edge to be the default for Edge browsers * Move code so that it is reachable * Fix usage of options to RemoteWebDriver (#9240) * Deprecate using a Firefox profile in Options * use attribute endpoint to evaluate multiple selects * implement get_dom_attribute * Add attribute_to_be_include method to expected_conditions when the at… (#9200) * Additional Python type hints (#9192) * Correct Type Hinting on option method. Fixes #9210 * Use a flat namespace for selenium options * remove unused imports * Add ARIA APIs for getting the role and label of an Element * Fix homepage attribute in wheel target * Avoid using bazel native python rules Selenium 4.0 Beta 1 * Deprecate all but `Options` and `Service` arguments in driver instantiation. (#9125,#9128) * Upgrade Bazel rules_python to latest * Deprecate w3c checks in python bindings (#9109) * Remove legacy WebElement key `ELEMENT` (#9102, #9110) * Improve how desired_capabilities and options are merged * Use weakreferences for driver in switch and mobile classes (#2425) * Fix 'webview2' browser name for Edge py options. (#9090) * Add python type hinting * Improved alias for Keys (#9076) * Improve comment about using importlib_resources * Add mozdebugger capability to use CDP Features with Firefox * Refactor bidi APIs for logging to be on their own class * Make sure we are checking a string for local file detector * Add Ignored Exception to wait in Bidi Tests * Update tests * Adding Github Actions workflow for Python (#9031) * Fix WebDriver.start_session docstring to remove incorrect arguments (#9021) * Add Mutation Logging support * Pin Firefox bidi support to use the generated code for CDP 85 * Fix handling of generated code put into wheels * Modernise the python code around imports and conditionals * Support for float types in text fields (#8936) * Add print page command to python binding (#8903) * Add Chrome v88 to bidi support * Fix pytest macro to allow --test_args to pass through * Remove thread.join in testing webserver due to chromedriver issue 3654 * Fix grammar typos in exceptions.py (#8876) * Enforce python version in wheel when created. fixes #8863 * Correct proxy tests * Include readme in Wheel so it's rendered on Pypi Selenium 4.0 Alpha 7 * BREAKING CHANGE: Dropped support for python < 3.7 * Remove support for XBL in Firefox. * Correct formatting with JS fragment * Add debugpy to requirements * Fix uploading multiple files on remote driver (#7472) (#8734) * Correct docstring around find_element and find_elements. Fixes #8806 * Add the ability to ignore local proxys that are available * add script pinning to python bindings * Deprecate desired_capabilities property in favour of capabilities property * Update tests to use requirements file * Allow driver fixtures to be used in Chrome only tests * Update testing to use the latest pytest * do not update already set preference (#8692) * Added new argument creationflags in Service class for common, chrome, and firefox (#8647) * add se namespacing to file upload endpoint for all bindings (#8588) * Correct dependency management for code generator * Update host to connect to get a port. Fixes #8503 * Poll quicker for the driver when starting up. Fixes #8477 * Add support for DevTools APIs * Improve WebKitGTK and WPEWebKit support * Fix browserName typo for Edge WebView2 * Fix wheel generation for multiple python versions Selenium 4.0 Alpha 6 Post 2 * Correct usage of Abstract Base class in some instances * Correct build step for releasing Selenium 4.0 Alpha 6 * Add Abstract Base Class to WebElement and WebDriver #7127 (#8348) * Copy `acceptInsecureCerts` to Options for Firefox. Fixes #8261 * Correct check on DEFAULT_EXECUTABLE_PATH * Use ProxyManager instead of PoolManager in remote_connection (#8297) * Check offsets are cast to int. Fixes #7639 * Fixes an issue where IE server port is set '0' by default (#8294) * Favor Python3 constructs and Python 2.7 compatibility (#8290) * Remove Unused Arguments from Firefox * Fixup Firefox deprecations * Delete support for Blackberry Driver * Delete PhantomJS capabilities * Delete Android Driver support * Remove python crazyfun references * Enable and update Safari tests * Use same port in remote executor and service (#8255) * Update tests and docs to not use deprecated methods * mark various tests as failing in Firefox * Use callback functions instead callable objects as expected conditions (#7765) * Fix error in webelemet not created, verifying if is str or dict. (#3481) * verify command_executor ssl certificate by default (#6536) * Correct documentation for ChromiumDriver * Deprecating find_element(s)_* calls in event firing webdriver * Fixing path to selenium server for remote tests * Fixing relative locator constructor * Changing environment variable we use to check if the tests are running on travis * Fixing HSL to RGBa color converter * Deprecate use of AppCache APIs Selenium 4.0 Alpha 5 * Correct service usage in IE Binding. Fixes #7749 * Deprecate find_element(s)_by_* calls * Use a capability to switch engines for Edge (#8096) * Fix Flake8 errors * Add WPEWebKit driver (#6375) * update python_requires to only support python 2.7 and Python3.5+(#8085) * add the ability to generate a wheel via bazel * Add in support for page loading strategies for Options * Add the ability to get and set timeouts against a driver. Fixes #7738 * Correct Docstring import in WebDriverWait example. Fixes #7780 * Explicitly force timeout value to float in WebDriverWait. Fixes #8050 * Add support for relative locators * Fix clear actions in ActionChains (#7943) * Automate RemoteConnection subclass selection (#8010) * Fix capabilities to support macOS platform (#7980) * fix: DeprecationWarning of base64.encodestring() (#7446) * Build python code with Bazel * Parse python docstring example as code snippet * correct python_requires in setup * Fix grammar typo in exceptions.py (#7657) * Fixed references to chromedriver website Selenium 4.0 Alpha 3 * Fixing stacktrace parser to handle strings as well as objects * urllib throws on 404 so let's check the /status endpoint that returns 200 * Changing default command executor address to the address of TNG Grid * Fixing check of type of a returned element in a test for all_of condition * Implement logical expected conditions in Python (#7121) * Explicitly clear PoolManager by using context manager (#6878) * Fix invisibility_of_element expected condition init function (#7484) * fix docs build, add chromium and edge to docs * flake8 fixes * allow --browser-binary and --browser-args to be used with ChromiumEdge * Add support for the new MicrosoftEdge (#7459) * increase async script timeout from 0 as the w3c spec states to start time checking immediately * fix unit test for firefox options, proxy key should be outside of options * update to w3c compliant log endpoints * Remove 'resolve_ip' option from RemoteConnection (#1729,#2509) * Running python unit tests with bazel * Pass capabilities rather than options to the proxy object (#6620) * Adding full page screenshot feature for Firefox (#7182) * Added EventFiringWebElement to the isinstance check in the move_to method.(#6604) * Added socksVersion field in proxy class (#6983) * also clear w3c actions in ActionChains#reset_actions * fix edge webdriver init by deprecating edge_service in favor of service also fix warnings import in edge/webdriver * Removes old exception and dead code from py lib.(#7134) * Raise error for unsupported method for set_window_rect Selenium 4.0 Alpha 1 * Update driver initialisation to use service and option objects * turn on keep-alive by default for remote connections (#7072) * Fix ConnectionResetError * Add new Cast commands * Suggest download Microsoft Webdriver over HTTPS * Clear PoolManager in ‘remote_connection’ to ensure sockets are closed * remove --disable-gpu option for headless Chrome * Add support for the New Window command (#6873) * Update docstrings in Options classes to allow documentation to highlight Return values * Fix typos in select.py (#6925) * Remove native events handling code * Deleting unused imports, fixing flake8 issues * Remove unused port selection in IE Driver * Enabling tests xpassed in Chrome * Pretty-printing code samples * remove all deprecated methods and args from Python bindings * Fix DeprecationWarning: invalid escape sequence * Don't override browser options with desired capabilities by default in WebKitGTK (#6814) * Add WebKitGTK to API docs (#6815) * Subclass options classes from a common base class (#6522) * Update Sphinx (#6728) * WebDriverWait: update documentation for until and until_not (#6711) * Fix typo in description of WebDriver class (#6724) * add strictFileInteractability to acceptable W3C capabilities * Deprecate Blackberry Driver support * Fixing/tidying docstring. Selenium 3.141.0 * Bump version to a better approximation of Π * Improved Test build targets * fix os path in test for Windows * use 'NUL' for /dev/null on Windows * Update ctor docstrings to explain that a directory passed in is cloned. Fixes #6542 * Allow passing of service_args to Safari. Fixes #6459 * Remove element equals url * Improved WebExtension support Selenium 3.14.1 * Fix ability to set timeout for urllib3 (#6286) * get_cookie uses w3c endpoint when compliant * Remove body from GET requests (#6250) * Fix actions pause for fraction of a second (#6300) * Fixed input pausing for some actions methods * Capabilities can be set on Options classes * WebElement rect method is now forward compatible for OSS endpoints (#6355) * Deprecation warnings now have a stacklevel of 2 * keep_alive can now be set on Webdriver init (#6316) * isDisplayed atom is now used for all w3c compliant browser, fixing issue with Safari 12 Selenium 3.14.0 * Fix doc of URL-related ExpectedCondition (#6236) * Added ExpectedCondition invisibility_of_element * Swap out httplib for urllib3 * Be consistent with webdriver init kwarg service_log_path (#5725) Selenium 3.13.0 * Add executing Chrome devtools command (#5989) * fix incorrect w3c action encoding in python client (#6014) * Implement context manager for WebDriver * Stop sending "windowHandle" param in maximize_window command for w3c Selenium 3.12.0 * Add desired_capabilities keyword to IE and Firefox drivers for driver consistency * Fix bug with creating Safari webdriver instance (#5578) * Add support for Safari extension command * Deprecate Options `set_headless` methods in favor of property setter * Only set --disable-gpu for Chrome headless when on Windows * Add selenium User-Agent header (#5696) * Remote webdriver can now be started when passing options * All Options.to_capabilities now start with default DesiredCapabilities * Improve the error message that is raised when safaridriver cannot be found (#5739) * IeOptions class is now imported to selenium.webdriver * Remove the beta `authenticate` methods from `Alert` Selenium 3.11.0 No changes just keeping python version in step with the rest of the project. Selenium 3.10.0 * make tests to check clicking on disabled element work for w3c compliant drivers (#5561) * add docstring for InvalidElementStateException. Fixes #5520 * Deleting unused imports * Making python specification in IDEA project more generic * It should be possible to use a custom safaridriver executable to run Selenium's test suite. Selenium 3.9.0 * Add docstrings to WebElement find methods (#5384) * Additional data in unexpected alert error is now handled for w3c drivers (#5416) * Allow service_args to be passed into Firefox WebDriver (#5421) * Fix bug introduced with response logging in 3.8.1 (#5362) Selenium 3.8.1 * Fix bug when creating an Opera driver (#5266) * Stop sending sessionId in w3c payload. (#4620) * Fix issue with w3c actions releasing on element (#5180) * A more descriptive log message is displayed if the port cannot be connected (#2913) * Initialize Alert object by calling alert.text (#1863) * PhantomJS is now deprecated, please use either Chrome or Firefox in headless mode * Legacy Firefox driver: ensuring copy of profile dir, its 'extensions' subdir and 'user.js' file are writable. (#1466) Selenium 3.8.0 * Firefox options can now be imported from selenium.webdriver as FirefoxOptions (#5120) * Headless mode can now be set in Chrome Options using `set_headless` * Headless mode can now be set in Firefox Options using `set_headless` * Add the WebKitGTK WebDriver and options class (#4635) * Browser options can now be passed to remote WebDriver via the `options` parameter * Browser option parameters are now standardized across drivers as `options`. `firefox_options`, `chrome_options`, and `ie_options` are now deprecated * Added missing W3C Error Codes (#4556) * Support has been removed for Python versions 2.6 and 3.3 Selenium 3.7.0 * need to pass applicable environment variables to tox * Fix active_element for w3c drivers (#3979) * add support for minimize command * add support for fullscreen command * window rect commands should fail on firefox and remote (legacy) * Fix python backward compatibility for window commands (#4937) * Update docstrings to specify the type of path needed to install firefox addons. (#4881) * Update python chromeOptions key for capabilities (#4622) * Fix python pause action implementation (#4795) Selenium 3.6.0 * Fix package name in python webelement module (#4670) * Fix python driver examples (#3872) * No need to multiply pause by 1000 * Add pause to action chains * only check for proxyType once * lowercase proxy type for w3c payload in python #4574 * guarding against null return value from find_elements in python #4555 * remove unnecessary pytest marking, address flake8 issues * allow IE WebDriver to accept IE Options * add IE Options class * convert OSS capabilities to W3C equivalent for W3C payload * Add Safari to API docs Selenium 3.5.0 * Numerous test fixes *Iterate over capabilities in a way to support py2.7 and py3 * Fix W3C switching to window by name. * Support GeckoDriver addon install/uninstall commands #4215. * Move firefox_profile into moz:firefoxOptions. * Filter non-W3C capability names out of alwaysMatch. * Honor cmd line args passed to Service ctor (#4167) * Add expected conditions based on URL to Python Expected Conditions #4160 * Add network emulation to Chrome Python bindings (#4011) * add warning when saving incorrectly named screenshot (#4141) Selenium 3.4.3 * Fix EventFiringWebdriver and WebElement to raise AttributeError on missing attributes. (#4107) * unwrap WebElements inside dicts Selenium 3.4.2 * translate move_by_offset command to w3c * Update capabilities properly instead of assuming dict structure. Fixes #3927 * Add missing file for Chrome options to API docs. * Add Chrome options module to API docs. Selenium 3.4.1 * Add back the ability to set profile when using Firefox 45ESR. Fixes #3897 Selenium 3.4.0 * Correct usage of newSession around `firstMatch` and `alwaysMatch` * Remove superfluous capabilities that are not needed * Add expected condition that waits for all found elements to be visible (#3532) * Allow methods wrapped by EventFiringWebDriver and EventFiringWebElement (#806) * Dropping `javascriptEnabled` capability for real browsers * Use W3C check from parent object instead of assuming from capabilities * Bump example source distribution to match latest release. * Replace TypeError with KeyError in remote webdriver error handler code (#3826) * When testing Marionette use default capabilities in testing * Conform to the api of urllib2 for adding header for a request (#3803) * Add `text` key to alert#sendKeys parameters for W3C Endpoint * Location once scrolled into view should use W3C executeScript endpoint not JSONWP * Fixed the usage information in documentation of "save_screenshot". (#3804) * Add Element Not Interactable exception * Clean up imports in error handler * flake8 cleanup Selenium 3.3.3 * make w3c execute_script commands unique Selenium 3.3.2 * Update window commands to use W3C End points * Update Alert when in W3C mode to use W3C Endpoints * Update to new W3C Execute Script end points * Add setting/getting proxy details to Firefox Options * Deprecate the use of browser profile when instantiating a session * Update start session to handle the W3C New Session * Add get/set window rect commands * Add InvalidArgumentException * When passing in `text` to send_keys, make sure we send a string not array * Fix string decoding in remote connection (#3663) * Fix indentation to satisfy PEP8 * Try use old way of setting page load timeout if new way fails. Fixes #3654 * fix file uploads for Firefox * Run unit tests on Python 3.3, 3.4, and 3.5 (#3638) * Fix indentation in double_click. * Fix non-W3C page load timeout setting. Selenium 3.3.1 * Fix encoding of basic auth header when using Python 3 Fixes #3622 * Add initial unit test suite * Update W3C Timeout setting to be in line with the specification * support.ui.Select class inherits from object (#3067) * fix bug in proxy constructor that some properties are not proper set (#3459) * Fix flake8 issues (#3628) Selenium 3.3.0 **Note** If you are updating to this version, please also update GeckoDriver to v0.15.0 * Fix python HTTPS encoding for python driver (#3379) * Allow Firefox preferences to be set directly in Options * Fix shutdown and process termination (#3263) * Preventing exception if log_path is none or empty. Fixes #3128 * Add the W3C capability to Firefox for accepting insecure certificates * Initial implementation of Pointer Actions * Only skip tests if driver name matches a directory name. * Update calls that return a pure object with keys to look for 'value' key * Initial W3C Actions support * fix docs output directory Selenium 3.0.2 * Add support for W3C Get Active Element * Return when we use executeScript for faking WebElement.get_property * Expand user paths and resolve absolute path for Chrome extensions * Add support for verbose logging and custom path to EdgeDriver * Update TakeElementScreenshot to match WebDriver specification * Raise WebDriverException when FirefoxBinary fails to locate binary * Fix getting IP for python 3 * Write Service log to DEVNULL by default * Only attempt to remove the Firefox profile path if one was specified * Added context manager for chrome/content in Firefox Selenium 3.0.1 * Fix regressions with python 3 * Add support for Safari Technology Preview Selenium 3.0.0 * new FirefoxDriver ctor precedence logic and moz:firefoxOptions support (#2882) * Add W3C Set Window Position and W3C Get Window Position * enable log path setting from firefox webdriver (#2700) * Correct encoding of getAttribute.js and only load it once. Fixes #2785 * Encode the isDisplayed atom and only load it once Selenium 3.0.0.b3 * Use atoms for get_attribute and is_displayed when communicating with a w3c compliant remote end. * Make it possible to specialise web element Selenium 3.0.0.b2 * Updated Marionette port argument to match other drivers. Selenium 3.0.0.b1 * Fix basestring reference to work with python 3. Fixes #1820 * Correct Length conditional when filtering in PhantomJS. Fixes #1817 * Fix send keys when using PUA keys e.g. Keys.RIGHT #1839 * Fix cookie file leak in PhantomJS #1854 * Use the correct binary path when using Marionette * Fixed: Unhelpful error message when PhantomJS exits. (#2173 #2168) * Fix broken link to python documentation (#2159) * Attempt to remove Firefox profile when using Marionette * Ensure all capabilities are either within desiredCapabilities or requiredCapabilities * Correct the expected capability name for the Firefox profile * Add Firefox options to capabilities * Visibility_of_all implies it only returns elements if all visible (#2052) * Find visible elements (#2041) * Pass the firefox_profile as a desired capability in the Python client when using a remote server * Avoid checking exception details for invalid locators due to differences in server implementations * Handle capabilities better with Marionette and GeckoDriver * Updated the maxVersion of FirefoxDriver xpi maxVersion to work with Firefox 47.0.1 * Remove Selenium RC support Selenium 2.53.0 * Adding Options object for use with Python FirefoxDriver * Fixed improper usage of super in exceptions module * create a temp file for cookies in phantomjs if not specified * Pass in the executable that FirefoxBinary finds to the service if there isn't one passed in as a kwarg or capability * Applied some DRY and extracted out the keys_to_typing() * Fix deselecting options in elements, not on {webelement.tag_name}") self._el = webelement multi = self._el.get_dom_attribute("multiple") self.is_multiple = multi and multi != "false" @property def options(self) -> List[WebElement]: """Returns a list of all options belonging to this select tag.""" return self._el.find_elements(By.TAG_NAME, "option") @property def all_selected_options(self) -> List[WebElement]: """Returns a list of all selected options belonging to this select tag.""" return [opt for opt in self.options if opt.is_selected()] @property def first_selected_option(self) -> WebElement: """The first selected option in this select tag (or the currently selected option in a normal select)""" for opt in self.options: if opt.is_selected(): return opt raise NoSuchElementException("No options are selected") def select_by_value(self, value: str) -> None: """Select all options that have a value matching the argument. That is, when given "foo" this would select an option like: :Args: - value - The value to match against throws NoSuchElementException If there is no option with specified value in SELECT """ css = f"option[value ={self._escape_string(value)}]" opts = self._el.find_elements(By.CSS_SELECTOR, css) matched = False for opt in opts: self._set_selected(opt) if not self.is_multiple: return matched = True if not matched: raise NoSuchElementException(f"Cannot locate option with value: {value}") def select_by_index(self, index: int) -> None: """Select the option at the given index. This is done by examining the "index" attribute of an element, and not merely by counting. :Args: - index - The option at this index will be selected throws NoSuchElementException If there is no option with specified index in SELECT """ match = str(index) for opt in self.options: if opt.get_attribute("index") == match: self._set_selected(opt) return raise NoSuchElementException(f"Could not locate element with index {index}") def select_by_visible_text(self, text: str) -> None: """Select all options that display text matching the argument. That is, when given "Bar" this would select an option like: :Args: - text - The visible text to match against throws NoSuchElementException If there is no option with specified text in SELECT """ xpath = f".//option[normalize-space(.) = {self._escape_string(text)}]" opts = self._el.find_elements(By.XPATH, xpath) matched = False for opt in opts: self._set_selected(opt) if not self.is_multiple: return matched = True if len(opts) == 0 and " " in text: sub_string_without_space = self._get_longest_token(text) if sub_string_without_space == "": candidates = self.options else: xpath = f".//option[contains(.,{self._escape_string(sub_string_without_space)})]" candidates = self._el.find_elements(By.XPATH, xpath) for candidate in candidates: if text == candidate.text: self._set_selected(candidate) if not self.is_multiple: return matched = True if not matched: raise NoSuchElementException(f"Could not locate element with visible text: {text}") def deselect_all(self) -> None: """Clear all selected entries. This is only valid when the SELECT supports multiple selections. throws NotImplementedError If the SELECT does not support multiple selections """ if not self.is_multiple: raise NotImplementedError("You may only deselect all options of a multi-select") for opt in self.options: self._unset_selected(opt) def deselect_by_value(self, value: str) -> None: """Deselect all options that have a value matching the argument. That is, when given "foo" this would deselect an option like: :Args: - value - The value to match against throws NoSuchElementException If there is no option with specified value in SELECT """ if not self.is_multiple: raise NotImplementedError("You may only deselect options of a multi-select") matched = False css = f"option[value = {self._escape_string(value)}]" opts = self._el.find_elements(By.CSS_SELECTOR, css) for opt in opts: self._unset_selected(opt) matched = True if not matched: raise NoSuchElementException(f"Could not locate element with value: {value}") def deselect_by_index(self, index: int) -> None: """Deselect the option at the given index. This is done by examining the "index" attribute of an element, and not merely by counting. :Args: - index - The option at this index will be deselected throws NoSuchElementException If there is no option with specified index in SELECT """ if not self.is_multiple: raise NotImplementedError("You may only deselect options of a multi-select") for opt in self.options: if opt.get_attribute("index") == str(index): self._unset_selected(opt) return raise NoSuchElementException(f"Could not locate element with index {index}") def deselect_by_visible_text(self, text: str) -> None: """Deselect all options that display text matching the argument. That is, when given "Bar" this would deselect an option like: :Args: - text - The visible text to match against """ if not self.is_multiple: raise NotImplementedError("You may only deselect options of a multi-select") matched = False xpath = f".//option[normalize-space(.) = {self._escape_string(text)}]" opts = self._el.find_elements(By.XPATH, xpath) for opt in opts: self._unset_selected(opt) matched = True if not matched: raise NoSuchElementException(f"Could not locate element with visible text: {text}") def _set_selected(self, option) -> None: if not option.is_selected(): if not option.is_enabled(): raise NotImplementedError("You may not select a disabled option") option.click() def _unset_selected(self, option) -> None: if option.is_selected(): option.click() def _escape_string(self, value: str) -> str: if '"' in value and "'" in value: substrings = value.split('"') result = ["concat("] for substring in substrings: result.append(f'"{substring}"') result.append(", '\"', ") result = result[0:-1] if value.endswith('"'): result.append(", '\"'") return "".join(result) + ")" if '"' in value: return f"'{value}'" return f'"{value}"' def _get_longest_token(self, value: str) -> str: items = value.split(" ") longest = "" for item in items: if len(item) > len(longest): longest = item return longest selenium-selenium-4.23.0/selenium/webdriver/support/wait.py0000664000175000017500000001230114646203155023771 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import time import typing from typing import Callable from typing import Generic from typing import Literal from typing import TypeVar from typing import Union from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import TimeoutException from selenium.types import WaitExcTypes from selenium.webdriver.remote.webdriver import WebDriver from selenium.webdriver.remote.webelement import WebElement POLL_FREQUENCY: float = 0.5 # How long to sleep in between calls to the method IGNORED_EXCEPTIONS: typing.Tuple[typing.Type[Exception]] = (NoSuchElementException,) # default to be ignored. D = TypeVar("D", bound=Union[WebDriver, WebElement]) T = TypeVar("T") class WebDriverWait(Generic[D]): def __init__( self, driver: D, timeout: float, poll_frequency: float = POLL_FREQUENCY, ignored_exceptions: typing.Optional[WaitExcTypes] = None, ): """Constructor, takes a WebDriver instance and timeout in seconds. :Args: - driver - Instance of WebDriver (Ie, Firefox, Chrome or Remote) or a WebElement - timeout - Number of seconds before timing out - poll_frequency - sleep interval between calls By default, it is 0.5 second. - ignored_exceptions - iterable structure of exception classes ignored during calls. By default, it contains NoSuchElementException only. Example:: from selenium.webdriver.support.wait import WebDriverWait \n element = WebDriverWait(driver, 10).until(lambda x: x.find_element(By.ID, "someId")) \n is_disappeared = WebDriverWait(driver, 30, 1, (ElementNotVisibleException)).\\ \n until_not(lambda x: x.find_element(By.ID, "someId").is_displayed()) """ self._driver = driver self._timeout = float(timeout) self._poll = poll_frequency # avoid the divide by zero if self._poll == 0: self._poll = POLL_FREQUENCY exceptions = list(IGNORED_EXCEPTIONS) if ignored_exceptions: try: exceptions.extend(iter(ignored_exceptions)) except TypeError: # ignored_exceptions is not iterable exceptions.append(ignored_exceptions) self._ignored_exceptions = tuple(exceptions) def __repr__(self): return f'<{type(self).__module__}.{type(self).__name__} (session="{self._driver.session_id}")>' def until(self, method: Callable[[D], Union[Literal[False], T]], message: str = "") -> T: """Calls the method provided with the driver as an argument until the \ return value does not evaluate to ``False``. :param method: callable(WebDriver) :param message: optional message for :exc:`TimeoutException` :returns: the result of the last call to `method` :raises: :exc:`selenium.common.exceptions.TimeoutException` if timeout occurs """ screen = None stacktrace = None end_time = time.monotonic() + self._timeout while True: try: value = method(self._driver) if value: return value except self._ignored_exceptions as exc: screen = getattr(exc, "screen", None) stacktrace = getattr(exc, "stacktrace", None) time.sleep(self._poll) if time.monotonic() > end_time: break raise TimeoutException(message, screen, stacktrace) def until_not(self, method: Callable[[D], T], message: str = "") -> Union[T, Literal[True]]: """Calls the method provided with the driver as an argument until the \ return value evaluates to ``False``. :param method: callable(WebDriver) :param message: optional message for :exc:`TimeoutException` :returns: the result of the last call to `method`, or ``True`` if `method` has raised one of the ignored exceptions :raises: :exc:`selenium.common.exceptions.TimeoutException` if timeout occurs """ end_time = time.monotonic() + self._timeout while True: try: value = method(self._driver) if not value: return value except self._ignored_exceptions: return True time.sleep(self._poll) if time.monotonic() > end_time: break raise TimeoutException(message) selenium-selenium-4.23.0/selenium/webdriver/support/abstract_event_listener.py0000664000175000017500000000420214646203155027737 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. class AbstractEventListener: """Event listener must subclass and implement this fully or partially.""" def before_navigate_to(self, url: str, driver) -> None: pass def after_navigate_to(self, url: str, driver) -> None: pass def before_navigate_back(self, driver) -> None: pass def after_navigate_back(self, driver) -> None: pass def before_navigate_forward(self, driver) -> None: pass def after_navigate_forward(self, driver) -> None: pass def before_find(self, by, value, driver) -> None: pass def after_find(self, by, value, driver) -> None: pass def before_click(self, element, driver) -> None: pass def after_click(self, element, driver) -> None: pass def before_change_value_of(self, element, driver) -> None: pass def after_change_value_of(self, element, driver) -> None: pass def before_execute_script(self, script, driver) -> None: pass def after_execute_script(self, script, driver) -> None: pass def before_close(self, driver) -> None: pass def after_close(self, driver) -> None: pass def before_quit(self, driver) -> None: pass def after_quit(self, driver) -> None: pass def on_exception(self, exception, driver) -> None: pass selenium-selenium-4.23.0/selenium/webdriver/support/relative_locator.py0000664000175000017500000001605214646203155026372 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from typing import Dict from typing import List from typing import NoReturn from typing import Optional from typing import Union from typing import overload from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By from selenium.webdriver.common.by import ByType from selenium.webdriver.remote.webelement import WebElement def with_tag_name(tag_name: str) -> "RelativeBy": """Start searching for relative objects using a tag name. Note: This method may be removed in future versions, please use `locate_with` instead. :Args: - tag_name: the DOM tag of element to start searching. :Returns: - RelativeBy - use this object to create filters within a `find_elements` call. """ if not tag_name: raise WebDriverException("tag_name can not be null") return RelativeBy({By.CSS_SELECTOR: tag_name}) def locate_with(by: ByType, using: str) -> "RelativeBy": """Start searching for relative objects your search criteria with By. :Args: - by: The value from `By` passed in. - using: search term to find the element with. :Returns: - RelativeBy - use this object to create filters within a `find_elements` call. """ assert by is not None, "Please pass in a by argument" assert using is not None, "Please pass in a using argument" return RelativeBy({by: using}) class RelativeBy: """Gives the opportunity to find elements based on their relative location on the page from a root elelemt. It is recommended that you use the helper function to create it. Example: lowest = driver.find_element(By.ID, "below") elements = driver.find_elements(locate_with(By.CSS_SELECTOR, "p").above(lowest)) ids = [el.get_attribute('id') for el in elements] assert "above" in ids assert "mid" in ids """ LocatorType = Dict[ByType, str] def __init__(self, root: Optional[Dict[ByType, str]] = None, filters: Optional[List] = None): """Creates a new RelativeBy object. It is preferred if you use the `locate_with` method as this signature could change. :Args: root - A dict with `By` enum as the key and the search query as the value filters - A list of the filters that will be searched. If none are passed in please use the fluent API on the object to create the filters """ self.root = root self.filters = filters or [] @overload def above(self, element_or_locator: Union[WebElement, LocatorType]) -> "RelativeBy": ... @overload def above(self, element_or_locator: None = None) -> "NoReturn": ... def above(self, element_or_locator: Union[WebElement, LocatorType, None] = None) -> "RelativeBy": """Add a filter to look for elements above. :Args: - element_or_locator: Element to look above """ if not element_or_locator: raise WebDriverException("Element or locator must be given when calling above method") self.filters.append({"kind": "above", "args": [element_or_locator]}) return self @overload def below(self, element_or_locator: Union[WebElement, LocatorType]) -> "RelativeBy": ... @overload def below(self, element_or_locator: None = None) -> "NoReturn": ... def below(self, element_or_locator: Union[WebElement, Dict, None] = None) -> "RelativeBy": """Add a filter to look for elements below. :Args: - element_or_locator: Element to look below """ if not element_or_locator: raise WebDriverException("Element or locator must be given when calling below method") self.filters.append({"kind": "below", "args": [element_or_locator]}) return self @overload def to_left_of(self, element_or_locator: Union[WebElement, LocatorType]) -> "RelativeBy": ... @overload def to_left_of(self, element_or_locator: None = None) -> "NoReturn": ... def to_left_of(self, element_or_locator: Union[WebElement, Dict, None] = None) -> "RelativeBy": """Add a filter to look for elements to the left of. :Args: - element_or_locator: Element to look to the left of """ if not element_or_locator: raise WebDriverException("Element or locator must be given when calling to_left_of method") self.filters.append({"kind": "left", "args": [element_or_locator]}) return self @overload def to_right_of(self, element_or_locator: Union[WebElement, LocatorType]) -> "RelativeBy": ... @overload def to_right_of(self, element_or_locator: None = None) -> "NoReturn": ... def to_right_of(self, element_or_locator: Union[WebElement, Dict, None] = None) -> "RelativeBy": """Add a filter to look for elements right of. :Args: - element_or_locator: Element to look right of """ if not element_or_locator: raise WebDriverException("Element or locator must be given when calling to_right_of method") self.filters.append({"kind": "right", "args": [element_or_locator]}) return self @overload def near(self, element_or_locator: Union[WebElement, LocatorType], distance: int = 50) -> "RelativeBy": ... @overload def near(self, element_or_locator: None = None, distance: int = 50) -> "NoReturn": ... def near(self, element_or_locator: Union[WebElement, LocatorType, None] = None, distance: int = 50) -> "RelativeBy": """Add a filter to look for elements near. :Args: - element_or_locator: Element to look near by the element or within a distance - distance: distance in pixel """ if not element_or_locator: raise WebDriverException("Element or locator must be given when calling near method") if distance <= 0: raise WebDriverException("Distance must be positive") self.filters.append({"kind": "near", "args": [element_or_locator, distance]}) return self def to_dict(self) -> Dict: """Create a dict that will be passed to the driver to start searching for the element.""" return { "relative": { "root": self.root, "filters": self.filters, } } selenium-selenium-4.23.0/selenium/webdriver/support/events.py0000664000175000017500000000163014646203155024334 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from .abstract_event_listener import AbstractEventListener # noqa from .event_firing_webdriver import EventFiringWebDriver # noqa selenium-selenium-4.23.0/selenium/webdriver/support/ui.py0000664000175000017500000000156614646203155023455 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from .select import Select from .wait import WebDriverWait __all__ = ["Select", "WebDriverWait"] selenium-selenium-4.23.0/selenium/webdriver/edge/0000775000175000017500000000000014646203155021646 5ustar carstencarstenselenium-selenium-4.23.0/selenium/webdriver/edge/__init__.py0000664000175000017500000000142314646203155023757 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.23.0/selenium/webdriver/edge/options.py0000664000175000017500000000323614646203155023717 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from selenium.webdriver.chromium.options import ChromiumOptions from selenium.webdriver.common.desired_capabilities import DesiredCapabilities class Options(ChromiumOptions): KEY = "ms:edgeOptions" def __init__(self) -> None: super().__init__() self._use_webview = False @property def use_webview(self) -> bool: return self._use_webview @use_webview.setter def use_webview(self, value: bool) -> None: self._use_webview = bool(value) def to_capabilities(self) -> dict: """Creates a capabilities with all the options that have been set and :Returns: A dictionary with everything.""" caps = super().to_capabilities() if self._use_webview: caps["browserName"] = "webview2" return caps @property def default_capabilities(self) -> dict: return DesiredCapabilities.EDGE.copy() selenium-selenium-4.23.0/selenium/webdriver/edge/service.py0000664000175000017500000000436614646203155023671 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import typing from selenium.types import SubprocessStdAlias from selenium.webdriver.chromium import service class Service(service.ChromiumService): """A Service class that is responsible for the starting and stopping of `msedgedriver`. :param executable_path: install path of the msedgedriver executable, defaults to `msedgedriver`. :param port: Port for the service to run on, defaults to 0 where the operating system will decide. :param verbose: (Deprecated) Whether to make the webdriver more verbose (passes the --verbose option to the binary). Defaults to False. :param log_output: (Optional) int representation of STDOUT/DEVNULL, any IO instance or String path to file. :param service_args: (Optional) List of args to be passed to the subprocess when launching the executable. :param env: (Optional) Mapping of environment variables for the new process, defaults to `os.environ`. """ def __init__( self, executable_path: str = None, port: int = 0, log_output: SubprocessStdAlias = None, service_args: typing.Optional[typing.List[str]] = None, env: typing.Optional[typing.Mapping[str, str]] = None, **kwargs, ) -> None: self.service_args = service_args or [] super().__init__( executable_path=executable_path, port=port, service_args=service_args, log_output=log_output, env=env, **kwargs, ) selenium-selenium-4.23.0/selenium/webdriver/edge/webdriver.py0000664000175000017500000000370014646203155024211 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from selenium.webdriver.chromium.webdriver import ChromiumDriver from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from .options import Options from .service import Service class WebDriver(ChromiumDriver): """Controls the MSEdgeDriver and allows you to drive the browser.""" def __init__( self, options: Options = None, service: Service = None, keep_alive: bool = True, ) -> None: """Creates a new instance of the edge driver. Starts the service and then creates new instance of edge driver. :Args: - options - this takes an instance of EdgeOptions - service - Service object for handling the browser driver if you need to pass extra details - keep_alive - Whether to configure EdgeRemoteConnection to use HTTP keep-alive. """ service = service if service else Service() options = options if options else Options() super().__init__( browser_name=DesiredCapabilities.EDGE["browserName"], vendor_prefix="ms", options=options, service=service, keep_alive=keep_alive, ) selenium-selenium-4.23.0/selenium/webdriver/edge/remote_connection.py0000664000175000017500000000270114646203155025732 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import typing from selenium.webdriver import DesiredCapabilities from selenium.webdriver.chromium.remote_connection import ChromiumRemoteConnection class EdgeRemoteConnection(ChromiumRemoteConnection): browser_name = DesiredCapabilities.EDGE["browserName"] def __init__( self, remote_server_addr: str, keep_alive: bool = True, ignore_proxy: typing.Optional[bool] = False, ) -> None: super().__init__( remote_server_addr=remote_server_addr, vendor_prefix="goog", browser_name=EdgeRemoteConnection.browser_name, keep_alive=keep_alive, ignore_proxy=ignore_proxy, ) selenium-selenium-4.23.0/selenium/webdriver/webkitgtk/0000775000175000017500000000000014646203155022735 5ustar carstencarstenselenium-selenium-4.23.0/selenium/webdriver/webkitgtk/__init__.py0000664000175000017500000000142314646203155025046 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.23.0/selenium/webdriver/webkitgtk/options.py0000664000175000017500000000513514646203155025006 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.common.options import ArgOptions class Options(ArgOptions): KEY = "webkitgtk:browserOptions" def __init__(self) -> None: super().__init__() self._binary_location = "" self._overlay_scrollbars_enabled = True @property def binary_location(self) -> str: """:Returns: The location of the browser binary otherwise an empty string.""" return self._binary_location @binary_location.setter def binary_location(self, value: str) -> None: """Allows you to set the browser binary to launch. :Args: - value : path to the browser binary """ self._binary_location = value @property def overlay_scrollbars_enabled(self): """:Returns: Whether overlay scrollbars should be enabled.""" return self._overlay_scrollbars_enabled @overlay_scrollbars_enabled.setter def overlay_scrollbars_enabled(self, value) -> None: """Allows you to enable or disable overlay scrollbars. :Args: - value : True or False """ self._overlay_scrollbars_enabled = value def to_capabilities(self): """Creates a capabilities with all the options that have been set and returns a dictionary with everything.""" caps = self._caps browser_options = {} if self.binary_location: browser_options["binary"] = self.binary_location if self.arguments: browser_options["args"] = self.arguments browser_options["useOverlayScrollbars"] = self.overlay_scrollbars_enabled caps[Options.KEY] = browser_options return caps @property def default_capabilities(self): return DesiredCapabilities.WEBKITGTK.copy() selenium-selenium-4.23.0/selenium/webdriver/webkitgtk/service.py0000664000175000017500000000440214646203155024747 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import typing from selenium.webdriver.common import service DEFAULT_EXECUTABLE_PATH = "WebKitWebDriver" class Service(service.Service): """A Service class that is responsible for the starting and stopping of `WPEWebDriver`. :param executable_path: install path of the WebKitWebDriver executable, defaults to `WebKitWebDriver`. :param port: Port for the service to run on, defaults to 0 where the operating system will decide. :param service_args: (Optional) List of args to be passed to the subprocess when launching the executable. :param log_path: (Optional) File path for the file to be opened and passed as the subprocess stdout/stderr handler. :param env: (Optional) Mapping of environment variables for the new process, defaults to `os.environ`. """ def __init__( self, executable_path: str = DEFAULT_EXECUTABLE_PATH, port: int = 0, log_path: typing.Optional[str] = None, service_args: typing.Optional[typing.List[str]] = None, env: typing.Optional[typing.Mapping[str, str]] = None, **kwargs, ): self.service_args = service_args or [] log_file = open(log_path, "wb") if log_path else None super().__init__( executable_path=executable_path, port=port, log_file=log_file, env=env, **kwargs, ) # type: ignore def command_line_args(self) -> typing.List[str]: return ["-p", f"{self.port}"] + self.service_args selenium-selenium-4.23.0/selenium/webdriver/webkitgtk/webdriver.py0000664000175000017500000000422614646203155025304 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import http.client as http_client from selenium.webdriver.common.driver_finder import DriverFinder from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver from .options import Options from .service import Service class WebDriver(RemoteWebDriver): """Controls the WebKitGTKDriver and allows you to drive the browser.""" def __init__( self, options=None, service: Service = None, ): """Creates a new instance of the WebKitGTK driver. Starts the service and then creates new instance of WebKitGTK Driver. :Args: - options : an instance of WebKitGTKOptions - service : Service object for handling the browser driver if you need to pass extra details """ options = options if options else Options() self.service = service if service else Service() self.service.path = DriverFinder(self.service, options).get_driver_path() self.service.start() super().__init__(command_executor=self.service.service_url, options=options) self._is_remote = False def quit(self): """Closes the browser and shuts down the WebKitGTKDriver executable that is started when starting the WebKitGTKDriver.""" try: super().quit() except http_client.BadStatusLine: pass finally: self.service.stop() selenium-selenium-4.23.0/selenium/webdriver/wpewebkit/0000775000175000017500000000000014646203155022743 5ustar carstencarstenselenium-selenium-4.23.0/selenium/webdriver/wpewebkit/__init__.py0000664000175000017500000000142314646203155025054 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.23.0/selenium/webdriver/wpewebkit/options.py0000664000175000017500000000423414646203155025013 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import typing from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.common.options import ArgOptions class Options(ArgOptions): KEY = "wpe:browserOptions" def __init__(self) -> None: super().__init__() self._binary_location = "" @property def binary_location(self) -> str: """Returns the location of the browser binary otherwise an empty string.""" return self._binary_location @binary_location.setter def binary_location(self, value: str) -> None: """Allows you to set the browser binary to launch. :Args: - value : path to the browser binary """ if not isinstance(value, str): raise TypeError(self.BINARY_LOCATION_ERROR) self._binary_location = value def to_capabilities(self): """Creates a capabilities with all the options that have been set and returns a dictionary with everything.""" caps = self._caps browser_options = {} if self.binary_location: browser_options["binary"] = self.binary_location if self.arguments: browser_options["args"] = self.arguments caps[Options.KEY] = browser_options return caps @property def default_capabilities(self) -> typing.Dict[str, str]: return DesiredCapabilities.WPEWEBKIT.copy() selenium-selenium-4.23.0/selenium/webdriver/wpewebkit/service.py0000664000175000017500000000436414646203155024764 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import shutil import typing from selenium.webdriver.common import service DEFAULT_EXECUTABLE_PATH = shutil.which("WPEWebDriver") class Service(service.Service): """A Service class that is responsible for the starting and stopping of `WPEWebDriver`. :param executable_path: install path of the WPEWebDriver executable, defaults to the first `WPEWebDriver` in `$PATH`. :param port: Port for the service to run on, defaults to 0 where the operating system will decide. :param service_args: (Optional) List of args to be passed to the subprocess when launching the executable. :param log_output: (Optional) File path for the file to be opened and passed as the subprocess stdout/stderr handler. :param env: (Optional) Mapping of environment variables for the new process, defaults to `os.environ`. """ def __init__( self, executable_path: str = DEFAULT_EXECUTABLE_PATH, port: int = 0, log_output: typing.Optional[str] = None, service_args: typing.Optional[typing.List[str]] = None, env: typing.Optional[typing.Mapping[str, str]] = None, **kwargs, ): self.service_args = service_args or [] super().__init__( executable_path=executable_path, port=port, log_output=log_output, env=env, **kwargs, ) # type: ignore def command_line_args(self) -> typing.List[str]: return ["-p", f"{self.port}"] + self.service_args selenium-selenium-4.23.0/selenium/webdriver/wpewebkit/webdriver.py0000664000175000017500000000423214646203155025307 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import http.client as http_client from selenium.webdriver.common.driver_finder import DriverFinder from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver from .options import Options from .service import Service class WebDriver(RemoteWebDriver): """Controls the WPEWebKitDriver and allows you to drive the browser.""" def __init__( self, options=None, service: Service = None, ): """Creates a new instance of the WPEWebKit driver. Starts the service and then creates new instance of WPEWebKit Driver. :Args: - options : an instance of ``WPEWebKitOptions`` - service : Service object for handling the browser driver if you need to pass extra details """ options = options if options else Options() self.service = service if service else Service() self.service.path = DriverFinder(self.service, options).get_driver_path() self.service.start() super().__init__(command_executor=self.service.service_url, options=options) self._is_remote = False def quit(self): """Closes the browser and shuts down the WPEWebKitDriver executable that is started when starting the WPEWebKitDriver.""" try: super().quit() except http_client.BadStatusLine: pass finally: self.service.stop() selenium-selenium-4.23.0/selenium/types.py0000664000175000017500000000176614646203155020501 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """Selenium type definitions.""" import typing AnyKey = typing.Union[str, int, float] WaitExcTypes = typing.Iterable[typing.Type[Exception]] # Service Types SubprocessStdAlias = typing.Union[int, str, typing.IO[typing.Any]] selenium-selenium-4.23.0/pyproject.toml0000664000175000017500000000014414646203155020043 0ustar carstencarsten[build-system] requires = ["setuptools", "setuptools-rust"] build-backend = "setuptools.build_meta" selenium-selenium-4.23.0/setup.py0000775000175000017500000000757314646203155016661 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from distutils.command.install import INSTALL_SCHEMES from os.path import dirname, join, abspath from setuptools import setup from setuptools.command.install import install from setuptools_rust import Binding, RustExtension for scheme in INSTALL_SCHEMES.values(): scheme['data'] = scheme['purelib'] setup_args = { 'cmdclass': {'install': install}, 'name': 'selenium', 'version': "4.23.0", 'license': 'Apache 2.0', 'description': 'Official Python bindings for Selenium WebDriver.', 'long_description': open(join(abspath(dirname(__file__)), "README.rst")).read(), 'url': 'https://github.com/SeleniumHQ/selenium/', 'project_urls': { 'Bug Tracker': 'https://github.com/SeleniumHQ/selenium/issues', 'Changes': 'https://github.com/SeleniumHQ/selenium/blob/trunk/py/CHANGES', 'Documentation': 'https://www.selenium.dev/documentation/overview/', 'Source Code': 'https://github.com/SeleniumHQ/selenium/tree/trunk/py', }, 'python_requires': '~=3.8', 'classifiers': ['Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: Apache Software License', 'Operating System :: POSIX', 'Operating System :: Microsoft :: Windows', 'Operating System :: MacOS :: MacOS X', 'Topic :: Software Development :: Testing', 'Topic :: Software Development :: Libraries', 'Programming Language :: Python', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', ], 'package_dir': { 'selenium': 'selenium', 'selenium.common': 'selenium/common', 'selenium.webdriver': 'selenium/webdriver', }, 'packages': ['selenium', 'selenium.common', 'selenium.webdriver', 'selenium.webdriver.chrome', 'selenium.webdriver.chromium', 'selenium.webdriver.common', 'selenium.webdriver.edge', 'selenium.webdriver.firefox', 'selenium.webdriver.ie', 'selenium.webdriver.remote', 'selenium.webdriver.safari', 'selenium.webdriver.support', 'selenium.webdriver.webkitgtk', 'selenium.webdriver.wpewebkit', ], 'include_package_data': True, 'install_requires': [ "urllib3[socks]>=1.26,<3", "trio~=0.17", "trio-websocket~=0.9", "certifi>=2021.10.8", "typing_extensions~= 4.9.0", "websocket-client==1.8.0", ], 'rust_extensions': [ RustExtension( {"selenium-manager": "selenium.webdriver.common.selenium-manager"}, binding=Binding.Exec ) ], 'zip_safe': False } setup(**setup_args) selenium-selenium-4.23.0/CONTRIBUTING.md0000664000175000017500000003003514646203155017362 0ustar carstencarsten# Contributing to Selenium The Selenium project welcomes contributions from everyone. There are a number of ways you can help: ## Bug Reports When opening new issues or commenting on existing issues please make sure discussions are related to concrete technical issues with the Selenium software. It's imperative that issue reports outline the steps to reproduce the defect. If the issue can't be reproduced it will be closed. Please provide [concise reproducible test cases](http://sscce.org/) and describe what results you are seeing and what results you expect. Issues shouldn't be used for support. Please address questions to the [`selenium-users@` mailing list](https://groups.google.com/forum/#!forum/selenium-users). Discussion of high level project ideas or non-technical topics should move to the [`selenium-developers@` mailing list](https://groups.google.com/forum/#!forum/selenium-developers) instead. We also need help with triaging [issues that needs investigation](https://github.com/SeleniumHQ/selenium/labels/I-needs%20investigation). This means asking the right questions, procuring the right information to properly debug and verify the issue, and bisecting a commit range if the issue is a regression. ## Feature Requests If you find that Selenium is missing something, feel free to open an issue with details describing what feature(s) you'd like added or changed. If you'd like a hand at trying to implement the feature yourself, please refer to the [Code Contributions](#code-contributions) section of the document. ## Documentation Selenium is a big software project and documentation is key to understanding how things work and learning effective ways to exploit its potential. The [seleniumhq.github.io](https://github.com/SeleniumHQ/seleniumhq.github.io/) repository contains both Selenium’s site and documentation. This is an ongoing effort (not targeted at any specific release) to provide updated information on how to use Selenium effectively, how to get involved and how to contribute to Selenium. The official documentation of Selenium is at https://selenium.dev/documentation/. More details on how to get involved and contribute, please check the site's and documentation [contributing guidelines](https://www.selenium.dev/documentation/about/contributing/). ## Code Contributions The Selenium project welcomes new contributors. Individuals making significant and valuable contributions over time are made _Committers_ and given commit-access to the project. If you're looking for easy bugs, have a look at [issues labelled E-easy](https://github.com/SeleniumHQ/selenium/issues?q=is%3Aopen+is%3Aissue+label%3AE-easy) on Github. This document will guide you through the contribution process. ### Step 1: Fork Fork the project [on Github](https://github.com/seleniumhq/selenium) and check out your copy locally. Use `--depth 1` for a quick check out. The repository is ~2GB and checking the whole history takes a while. ```shell % git clone git@github.com:username/selenium.git --depth 1 % cd selenium % git remote add upstream git://github.com/seleniumhq/selenium.git ``` #### Dependencies We bundle dependencies in the _third-party/_ directory that is not part of the proper project. Any changes to files in this directory or its subdirectories should be sent upstream to the respective projects. Please don't send your patch to us as we cannot accept it. We do accept help in upgrading our existing dependencies or removing superfluous dependencies. If you need to add a new dependency it's often a good idea to reach out to the committers on the [IRC channel or the mailing list](https://github.com/SeleniumHQ/selenium/blob/trunk/CONTRIBUTING.md#communication) to check that your approach aligns with the project's ideas. Nothing is more frustrating than seeing your hard work go to waste because your vision doesn't align with the project's. #### Dependencies Managed by Bazel ##### Java Edit `MODULE.bazel`, and either update or add the dependency you want using the regular maven coordinates to the `maven.install` with the name `maven`. Once done, run `REPIN=1 bazel run @maven//:pin` to update the lock file, create a PR and check the change in. ##### JS We use `pnpm` for JS development in the project, and we also use [pnpm workspaces](https://pnpm.io/workspaces). Take a look at the top-level `pnpm-workspace.yaml` file to find them all, but the main thing to know is that each of the workspaces has its own `package.json`. You can add dependencies to specific workspaces either by using `pnpm` installed on your local machine, or by executing: ```shell # Example of adding a dep to the JS webdriver bindings cd javascript/node/selenium-webdriver bazel run javascript:pnpm -- install my-amazing-dep --dir $PWD ``` This will install the dependency using the same version of `pnpm` we build the project with for a single JS project. To update all dependencies in the tree to the latest version: `bazel run javascript:pnpm -- -r up --dir $PWD` This will also update the lock file, so once a change is made, create a PR and commit all the changed files. #### License Headers Every file in the Selenium project must carry the following license header boilerplate: ```text Licensed to the Software Freedom Conservancy (SFC) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The SFC licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ``` There's no need to include a copyright statement in the file's header. The copyright attributions can be reviewed in the [NOTICE](https://github.com/SeleniumHQ/selenium/blob/trunk/NOTICE) file found in the top-level directory. ### Step 2: Branch Create a feature branch and start hacking: ```shell % git checkout -b my-feature-branch ``` We practice HEAD-based development, which means all changes are applied directly on top of trunk. ### Step 3: Commit First make sure git knows your name and email address: ```shell % git config --global user.name 'Santa Claus' % git config --global user.email 'santa@example.com' ``` **Writing good commit messages is important.** A commit message should describe what changed, why, and reference issues fixed (if any). Follow these guidelines when writing one: 1. The first line should be around 50 characters or less and contain a short description of the change. 2. Keep the second line blank. 3. Wrap all other lines at 72 columns. 4. Include `Fixes #N`, where _N_ is the issue number the commit fixes, if any. A good commit message can look like this: ```text explain commit normatively in one line Body of commit message is a few lines of text, explaining things in more detail, possibly giving some background about the issue being fixed, etc. The body of the commit message can be several paragraphs, and please do proper word-wrap and keep columns shorter than about 72 characters or so. That way `git log` will show things nicely even when it is indented. Fixes #141 ``` The first line must be meaningful as it's what people see when they run `git shortlog` or `git log --oneline`. ### Step 4: Rebase Use `git rebase` (not `git merge`) to sync your work from time to time. ```shell % git fetch upstream % git rebase upstream/trunk ``` ### Step 5: Test Bug fixes and features **should have tests**. Look at other tests to see how they should be structured. Verify that new and existing tests are passing locally before pushing code. #### Running tests locally Build your code for the latest changes and run tests locally. ##### Python
Click to see How to run Python Tests. It's not mandatory to run tests sequentially but running Unit tests before browser testing is recommended. Unit Tests ```shell % bazel test //py:unit ``` Remote Tests ```shell % bazel test --jobs 1 //py:test-remote ``` Browser Tests ```shell % bazel test //py:test- #eg test-chrome, test-firefox ```
##### Javascript
Click to see How to run JavaScript Tests. Node Tests ```shell % bazel test //javascript/node/selenium-webdriver:tests ``` Firefox Atom Tests ```shell % bazel test --test_tag_filters=firefox //javascript/atoms/... //javascript/selenium-atoms/... //javascript/webdriver/... ``` Grid UI Unit Tests ```shell % cd javascript/grid-ui && npm install && npm test ```
##### Java
Click to see How to run Java Tests. Small Tests ```shell % bazel test --cache_test_results=no --test_size_filters=small grid java/test/... ``` Large Tests ```shell % bazel test --cache_test_results=no java/test/org/openqa/selenium/grid/router:large-tests ``` Browser Tests ```shell bazel test --test_size_filters=small,medium --cache_test_results=no --test_tag_filters=-browser-test //java/... ```
##### Ruby Please see https://github.com/SeleniumHQ/selenium#ruby for details about running tests. ### Step 6: Push ```shell % git push origin my-feature-branch ``` Go to https://github.com/yourusername/selenium.git and press the _Pull Request_ and fill out the form. Pull requests are usually reviewed within a few days. If there are comments to address, apply your changes in new commits (preferably [fixups](http://git-scm.com/docs/git-commit)) and push to the same branch. ### Step 7: Integration When code review is complete, a committer will take your PR and integrate it on Selenium's trunk branch. Because we like to keep a linear history on the trunk branch, we will normally squash and rebase your branch history. ## Stages of an Issue or PR From your create your issue or pull request, through code review and towards integration, it will be assigned different Github labels. The labels serve for the committers to more easily keep track of work that's pending or awaiting action. Component labels are yellow and carry the **C** prefix. They highlight the subsystem or component your PR makes changes in. The driver labels (**D**) indicate if the changes are related to a WebDriver implementation or the Selenium atoms. The review labels (**R**) are: * **awaiting answer**: awaits an answer from you * **awaiting merge**: waits for a committer to integrate the PR * **awaiting reviewer**: pending code review * **blocked on external**: a change in an upstream repo is required * **needs code changes**: waiting for you to fix a review issue * **needs rebase**: the branch isn't in sync with trunk and needs to be rebased Issues are labelled to make them easier to categorise and find by: * which **component** they relate to (java, cpp, dotnet, py, rb, nodejs) * which **driver** is affected * their presumed **difficulty** (easy, less easy, hard) * what **type** of issue they are (defect, race condition, cleanup) ## Communication Selenium contributors frequent the `#selenium` channel on [`irc.freenode.org`](https://webchat.freenode.net/). You can also join the [`selenium-developers@` mailing list](https://groups.google.com/forum/#!forum/selenium-developers). Check https://selenium.dev/support/ for a complete list of options to communicate. ## Using the EngFlow RBE To access the EngFlow RBE, a developer needs to be granted access to our project container repository. Once that has been done, then any bazel command can be run remotely by using `--config=remote`. For example: `bazel build --config=remote grid` or `bazel test --config=remote java/test/...` When you run a remote build, one of the first lines of output from Bazel will include a link to the EngFlow UI so you can track the progress of the build and gather information about the efficiency of the build. selenium-selenium-4.23.0/setup.cfg0000664000175000017500000000046614646203155016757 0ustar carstencarsten[flake8] exclude = .tox,docs/source/conf.py,*venv # Disable this once black is applied throughout & line length is better handled. extend-ignore = E501, E203 # This does nothing for now as E501 is ignored. max-line-length = 120 [tool:pytest] addopts = -ra python_files = test_*.py *_tests.py testpaths = test selenium-selenium-4.23.0/docs/0000775000175000017500000000000014646203155016060 5ustar carstencarstenselenium-selenium-4.23.0/docs/source/0000775000175000017500000000000014646203155017360 5ustar carstencarstenselenium-selenium-4.23.0/docs/source/conf.py0000664000175000017500000002231614646203155020663 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import sys import os import os.path # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # sys.path.insert(0, os.path.abspath('.')) sys.path.insert(0, os.path.join(os.getcwd(), "..", "..")) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.autosummary', 'sphinx.ext.doctest', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.imgmath', 'sphinx.ext.viewcode'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = 'Selenium' copyright = '2009-2024 Software Freedom Conservancy' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '4.23' # The full version, including alpha/beta/rc tags. release = '4.23.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. html_show_sphinx = False # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'Seleniumdoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'Selenium.tex', 'Selenium Documentation', 'plightbo, simon.m.stewart, hbchai, jrhuggins, et al.', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'selenium', 'Selenium Documentation', ['plightbo, simon.m.stewart, hbchai, jrhuggins, et al.'], 1) ] # -- Options for Epub output --------------------------------------------------- # Bibliographic Dublin Core info. epub_title = 'Selenium' epub_author = 'The Selenium Project' epub_publisher = 'The Selenium Project' epub_copyright = '2009-2024 Software Freedom Conservancy' # The language of the text. It defaults to the language option # or en if the language is not set. #epub_language = '' # The scheme of the identifier. Typical schemes are ISBN or URL. #epub_scheme = '' # The unique identifier of the text. This can be a ISBN number # or the project homepage. #epub_identifier = '' # A unique identification for the text. #epub_uid = '' # HTML files that should be inserted before the pages created by sphinx. # The format is a list of tuples containing the path and title. #epub_pre_files = [] # HTML files that should be inserted after the pages created by sphinx. # The format is a list of tuples containing the path and title. #epub_post_files = [] # A list of files that should not be packed into the epub file. #epub_exclude_files = [] # The depth of the table of contents in toc.ncx. #epub_tocdepth = 3 # Allow duplicate toc entries. #epub_tocdup = True # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'http://docs.python.org/': None} # 'members' includes anything that has a docstring, 'undoc-members' includes # functions without docstrings. autodoc_default_flags = ['members', 'undoc-members'] # configuration for keeping the methods that can be invoked on said classes autodoc_default_options = { 'members': True, 'member-order': 'bysource', 'undoc-members': True, 'inherited-members': True, } # Include __init__ comments autoclass_content = "both" selenium-selenium-4.23.0/docs/source/index.rst0000775000175000017500000001350314646203155021226 0ustar carstencarsten====================== Selenium Client Driver ====================== Introduction ============ Python language bindings for Selenium WebDriver. The `selenium` package is used to automate web browser interaction from Python. +-----------------+--------------------------------------------------------------------------------------+ | **Home**: | https://selenium.dev | +-----------------+--------------------------------------------------------------------------------------+ | **GitHub**: | https://github.com/SeleniumHQ/Selenium | +-----------------+--------------------------------------------------------------------------------------+ | **PyPI**: | https://pypi.org/project/selenium/ | +-----------------+--------------------------------------------------------------------------------------+ | **IRC/Slack**: | `Selenium chat room `_ | +-----------------+--------------------------------------------------------------------------------------+ Several browsers/drivers are supported (Firefox, Chrome, Internet Explorer), as well as the Remote protocol. Supported Python Versions ========================= * Python 3.8+ Installing ========== If you have `pip `_ on your system, you can simply install or upgrade the Python bindings:: pip install -U selenium Alternately, you can download the source distribution from `PyPI `, unarchive it, and run:: python setup.py install Note: You may want to consider using `virtualenv `_ to create isolated Python environments. Drivers ======= Selenium requires a driver to interface with the chosen browser. Firefox, for example, requires `geckodriver `_, which needs to be installed before the below examples can be run. Make sure it's in your `PATH`, e. g., place it in `/usr/bin` or `/usr/local/bin`. Failure to observe this step will give you an error `selenium.common.exceptions.WebDriverException: Message: 'geckodriver' executable needs to be in PATH.` Other supported browsers will have their own drivers available. Links to some of the more popular browser drivers follow. +--------------+-----------------------------------------------------------------------+ | **Chrome**: | https://chromedriver.chromium.org/downloads | +--------------+-----------------------------------------------------------------------+ | **Edge**: | https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/ | +--------------+-----------------------------------------------------------------------+ | **Firefox**: | https://github.com/mozilla/geckodriver/releases | +--------------+-----------------------------------------------------------------------+ | **Safari**: | https://webkit.org/blog/6900/webdriver-support-in-safari-10/ | +--------------+-----------------------------------------------------------------------+ Example 0: ========== * open a new Firefox browser * load the page at the given URL .. code-block:: python from selenium import webdriver browser = webdriver.Firefox() browser.get('http://selenium.dev/') Example 1: ========== * open a new Firefox browser * load the Yahoo homepage * search for "seleniumhq" * close the browser .. code-block:: python from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys browser = webdriver.Firefox() browser.get('http://www.yahoo.com') assert 'Yahoo' in browser.title elem = browser.find_element(By.NAME, 'p') # Find the search box elem.send_keys('seleniumhq' + Keys.RETURN) browser.quit() Example 2: ========== Selenium WebDriver is often used as a basis for testing web applications. Here is a simple example using Python's standard `unittest `_ library: .. code-block:: python import unittest from selenium import webdriver class GoogleTestCase(unittest.TestCase): def setUp(self): self.browser = webdriver.Firefox() self.addCleanup(self.browser.quit) def test_page_title(self): self.browser.get('http://www.google.com') self.assertIn('Google', self.browser.title) if __name__ == '__main__': unittest.main(verbosity=2) Selenium Grid (optional) ========================== For local Selenium scripts, the Java server is not needed. To use Selenium remotely, you need to also run the Selenium grid. For information on running Selenium Grid: https://www.selenium.dev/documentation/grid/getting_started/ To use Remote WebDriver see: https://www.selenium.dev/documentation/webdriver/drivers/remote_webdriver/?tab=python Use The Source Luke! ==================== View source code online: +-----------+------------------------------------------------------+ | Official: | https://github.com/SeleniumHQ/selenium/tree/trunk/py | +-----------+------------------------------------------------------+ Contributing ============= - Create a branch for your work - Ensure `tox` is installed (using a `virtualenv` is recommended) - `python3.8 -m venv .venv && . .venv/bin/activate && pip install tox` - After making changes, before committing execute `tox -e linting` - If tox exits `0`, commit and push otherwise fix the newly introduced breakages. - `flake8` requires manual fixes - `black` will often rewrite the breakages automatically, however the files are unstaged and should staged again. - `isort` will often rewrite the breakages automatically, however the files are unstaged and should staged again. selenium-selenium-4.23.0/docs/source/api.rst0000664000175000017500000001207214646203155020665 0ustar carstencarsten:orphan: ====================== Selenium Documentation ====================== Common ------ .. currentmodule:: selenium.common .. autosummary:: :toctree: common selenium.common.exceptions Webdriver.common ---------------- .. currentmodule:: selenium.webdriver.common .. autosummary:: :toctree: webdriver selenium.webdriver.common.action_chains selenium.webdriver.common.alert selenium.webdriver.common.by selenium.webdriver.common.desired_capabilities selenium.webdriver.common.driver_finder selenium.webdriver.common.keys selenium.webdriver.common.log selenium.webdriver.common.options selenium.webdriver.common.print_page_options selenium.webdriver.common.proxy selenium.webdriver.common.selenium_manager selenium.webdriver.common.service selenium.webdriver.common.timeouts selenium.webdriver.common.utils selenium.webdriver.common.virtual_authenticator selenium.webdriver.common.window selenium.webdriver.common.actions.action_builder selenium.webdriver.common.actions.input_device selenium.webdriver.common.actions.interaction selenium.webdriver.common.actions.key_actions selenium.webdriver.common.actions.key_input selenium.webdriver.common.actions.mouse_button selenium.webdriver.common.actions.pointer_actions selenium.webdriver.common.actions.pointer_input selenium.webdriver.common.actions.wheel_actions selenium.webdriver.common.actions.wheel_input selenium.webdriver.common.bidi.cdp selenium.webdriver.common.bidi.console selenium.webdriver.common.bidi.script selenium.webdriver.common.bidi.session Webdriver.support ----------------- .. currentmodule:: selenium.webdriver.support .. autosummary:: :toctree: webdriver_support selenium.webdriver.support.abstract_event_listener selenium.webdriver.support.color selenium.webdriver.support.event_firing_webdriver selenium.webdriver.support.events selenium.webdriver.support.expected_conditions selenium.webdriver.support.relative_locator selenium.webdriver.support.select selenium.webdriver.support.ui selenium.webdriver.support.wait Webdriver.chrome ---------------- .. currentmodule:: selenium.webdriver.chrome .. autosummary:: :toctree: webdriver_chrome selenium.webdriver.chrome.options selenium.webdriver.chrome.remote_connection selenium.webdriver.chrome.service selenium.webdriver.chrome.webdriver Webdriver.chromium ------------------ .. currentmodule:: selenium.webdriver.chromium .. autosummary:: :toctree: webdriver_chromium selenium.webdriver.chromium.options selenium.webdriver.chromium.remote_connection selenium.webdriver.chromium.service selenium.webdriver.chromium.webdriver Webdriver.edge -------------- .. currentmodule:: selenium.webdriver.edge .. autosummary:: :toctree: webdriver_edge selenium.webdriver.edge.options selenium.webdriver.edge.remote_connection selenium.webdriver.edge.service selenium.webdriver.edge.webdriver Webdriver.firefox ----------------- .. currentmodule:: selenium.webdriver.firefox .. autosummary:: :toctree: webdriver_firefox selenium.webdriver.firefox.firefox_binary selenium.webdriver.firefox.firefox_profile selenium.webdriver.firefox.options selenium.webdriver.firefox.remote_connection selenium.webdriver.firefox.service selenium.webdriver.firefox.webdriver Webdriver.ie ------------ .. currentmodule:: selenium.webdriver.ie .. autosummary:: :toctree: webdriver_ie selenium.webdriver.ie.service selenium.webdriver.ie.options selenium.webdriver.ie.webdriver Webdriver.remote ---------------- .. currentmodule:: selenium.webdriver.remote .. autosummary:: :toctree: webdriver_remote selenium.webdriver.remote.bidi_connection selenium.webdriver.remote.command selenium.webdriver.remote.errorhandler selenium.webdriver.remote.file_detector selenium.webdriver.remote.mobile selenium.webdriver.remote.remote_connection selenium.webdriver.remote.script_key selenium.webdriver.remote.shadowroot selenium.webdriver.remote.switch_to selenium.webdriver.remote.utils selenium.webdriver.remote.webdriver selenium.webdriver.remote.webelement selenium.webdriver.remote.websocket_connection Webdriver.safari ---------------- .. currentmodule:: selenium.webdriver.safari .. autosummary:: :toctree: webdriver_safari selenium.webdriver.safari.options selenium.webdriver.safari.permissions selenium.webdriver.safari.remote_connection selenium.webdriver.safari.service selenium.webdriver.safari.webdriver Webdriver.wpewebkit ------------------- .. currentmodule:: selenium.webdriver.wpewebkit .. autosummary:: :toctree: webdriver_wpewebkit selenium.webdriver.wpewebkit.options selenium.webdriver.wpewebkit.service selenium.webdriver.wpewebkit.webdriver Webdriver.webkitgtk ------------------- .. currentmodule:: selenium.webdriver.webkitgtk .. autosummary:: :toctree: webdriver_webkitgtk selenium.webdriver.webkitgtk.options selenium.webdriver.webkitgtk.service selenium.webdriver.webkitgtk.webdriver Indices and tables * :ref:`genindex` * :ref:`modindex` * :ref:`search` selenium-selenium-4.23.0/docs/Makefile0000664000175000017500000001105714646203155017524 0ustar carstencarsten# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source HTML_DESTINATION = ../../docs/api/py .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: clean $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(HTML_DESTINATION) @echo @echo "Build finished. The HTML pages are in $(HTML_DESTINATION)." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Selenium.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Selenium.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/Selenium" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Selenium" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." make -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." selenium-selenium-4.23.0/docs/requirements.txt0000664000175000017500000000003414646203155021341 0ustar carstencarstenJinja2==3.1.4 Sphinx==7.1.2 selenium-selenium-4.23.0/conftest.py0000664000175000017500000002543314646203155017336 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import os import platform import socket import subprocess import time from test.selenium.webdriver.common.network import get_lan_ip from test.selenium.webdriver.common.webserver import SimpleWebServer from urllib.request import urlopen import pytest from selenium import webdriver drivers = ( "chrome", "edge", "firefox", "ie", "remote", "safari", "webkitgtk", "wpewebkit", ) def pytest_addoption(parser): parser.addoption( "--driver", action="append", choices=drivers, dest="drivers", metavar="DRIVER", help="driver to run tests against ({})".format(", ".join(drivers)), ) parser.addoption( "--browser-binary", action="store", dest="binary", help="location of the browser binary", ) parser.addoption( "--driver-binary", action="store", dest="executable", help="location of the service executable binary", ) parser.addoption( "--browser-args", action="store", dest="args", help="arguments to start the browser with", ) parser.addoption( "--headless", action="store", dest="headless", help="Allow tests to run in headless", ) parser.addoption( "--use-lan-ip", action="store_true", dest="use_lan_ip", help="Whether to start test server with lan ip instead of localhost", ) parser.addoption( "--bidi", action="store", dest="bidi", metavar="BIDI", help="Whether to enable BiDi support", ) def pytest_ignore_collect(path, config): drivers_opt = config.getoption("drivers") _drivers = set(drivers).difference(drivers_opt or drivers) if drivers_opt: _drivers.add("unit") parts = path.dirname.split(os.path.sep) return len([d for d in _drivers if d.lower() in parts]) > 0 driver_instance = None @pytest.fixture(scope="function") def driver(request): kwargs = {} # browser can be changed with `--driver=firefox` as an argument or to addopts in pytest.ini driver_class = getattr(request, "param", "Chrome").capitalize() # skip tests if not available on the platform _platform = platform.system() if driver_class == "Safari" and _platform != "Darwin": pytest.skip("Safari tests can only run on an Apple OS") if (driver_class == "Ie") and _platform != "Windows": pytest.skip("IE and EdgeHTML Tests can only run on Windows") if "WebKit" in driver_class and _platform != "Linux": pytest.skip("Webkit tests can only run on Linux") # conditionally mark tests as expected to fail based on driver marker = request.node.get_closest_marker(f"xfail_{driver_class.lower()}") if marker is not None: if "run" in marker.kwargs: if marker.kwargs["run"] is False: pytest.skip() yield return if "raises" in marker.kwargs: marker.kwargs.pop("raises") pytest.xfail(**marker.kwargs) def fin(): global driver_instance if driver_instance is not None: driver_instance.quit() driver_instance = None request.addfinalizer(fin) driver_path = request.config.option.executable options = None global driver_instance if driver_instance is None: if driver_class == "Firefox": options = get_options(driver_class, request.config) if driver_class == "Chrome": options = get_options(driver_class, request.config) if driver_class == "Remote": options = get_options("Firefox", request.config) or webdriver.FirefoxOptions() options.set_capability("moz:firefoxOptions", {}) options.enable_downloads = True if driver_class == "WebKitGTK": options = get_options(driver_class, request.config) if driver_class == "Edge": options = get_options(driver_class, request.config) if driver_class.lower() == "wpewebkit": driver_class = "WPEWebKit" options = get_options(driver_class, request.config) if driver_path is not None: kwargs["service"] = get_service(driver_class, driver_path) if options is not None: kwargs["options"] = options driver_instance = getattr(webdriver, driver_class)(**kwargs) yield driver_instance # Close the browser after BiDi tests. Those make event subscriptions # and doesn't seems to be stable enough, causing the flakiness of the # subsequent tests. # Remove this when BiDi implementation and API is stable. if bool(request.config.option.bidi): def fin(): global driver_instance if driver_instance is not None: driver_instance.quit() driver_instance = None request.addfinalizer(fin) if request.node.get_closest_marker("no_driver_after_test"): driver_instance = None def get_options(driver_class, config): browser_path = config.option.binary browser_args = config.option.args headless = bool(config.option.headless) bidi = bool(config.option.bidi) options = None if browser_path or browser_args: if not options: options = getattr(webdriver, f"{driver_class}Options")() if driver_class == "WebKitGTK": options.overlay_scrollbars_enabled = False if browser_path is not None: options.binary_location = browser_path.strip("'") if browser_args is not None: for arg in browser_args.split(): options.add_argument(arg) if headless: if not options: options = getattr(webdriver, f"{driver_class}Options")() if driver_class == "Chrome" or driver_class == "Edge": options.add_argument("--headless=new") if driver_class == "Firefox": options.add_argument("-headless") if bidi: if not options: options = getattr(webdriver, f"{driver_class}Options")() options.web_socket_url = True return options def get_service(driver_class, executable): # Let the default behaviour be used if we don't set the driver executable if not executable: return None module = getattr(webdriver, driver_class.lower()) service = module.service.Service(executable_path=executable) return service @pytest.fixture(scope="session", autouse=True) def stop_driver(request): def fin(): global driver_instance if driver_instance is not None: driver_instance.quit() driver_instance = None request.addfinalizer(fin) def pytest_exception_interact(node, call, report): if report.failed: global driver_instance if driver_instance is not None: driver_instance.quit() driver_instance = None @pytest.fixture def pages(driver, webserver): class Pages: def url(self, name, localhost=False): return webserver.where_is(name, localhost) def load(self, name): driver.get(self.url(name)) return Pages() @pytest.fixture(autouse=True, scope="session") def server(request): drivers = request.config.getoption("drivers") if drivers is None or "remote" not in drivers: yield None return _host = "localhost" _port = 4444 _path = os.path.join( os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "java/src/org/openqa/selenium/grid/selenium_server_deploy.jar", ) def wait_for_server(url, timeout): start = time.time() while time.time() - start < timeout: try: urlopen(url) return 1 except OSError: time.sleep(0.2) return 0 _socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) url = f"http://{_host}:{_port}/status" try: _socket.connect((_host, _port)) print( "The remote driver server is already running or something else" "is using port {}, continuing...".format(_port) ) except Exception: print("Starting the Selenium server") process = subprocess.Popen( [ "java", "-jar", _path, "standalone", "--port", "4444", "--selenium-manager", "true", "--enable-managed-downloads", "true", ] ) print(f"Selenium server running as process: {process.pid}") assert wait_for_server(url, 10), f"Timed out waiting for Selenium server at {url}" print("Selenium server is ready") yield process process.terminate() process.wait() print("Selenium server has been terminated") @pytest.fixture(autouse=True, scope="session") def webserver(request): host = get_lan_ip() if request.config.getoption("use_lan_ip") else "0.0.0.0" webserver = SimpleWebServer(host=host) webserver.start() yield webserver webserver.stop() @pytest.fixture def edge_service(): from selenium.webdriver.edge.service import Service as EdgeService return EdgeService @pytest.fixture(scope="function") def driver_executable(request): return request.config.option.executable @pytest.fixture(scope="function") def clean_service(request): try: driver_class = request.config.option.drivers[0].capitalize() except AttributeError: raise Exception("This test requires a --driver to be specified.") yield get_service(driver_class, request.config.option.executable) @pytest.fixture(scope="function") def clean_driver(request): try: driver_class = request.config.option.drivers[0].capitalize() except AttributeError: raise Exception("This test requires a --driver to be specified.") driver_reference = getattr(webdriver, driver_class) yield driver_reference if request.node.get_closest_marker("no_driver_after_test"): driver_reference = None selenium-selenium-4.23.0/python.iml0000664000175000017500000000223214646203155017153 0ustar carstencarsten selenium-selenium-4.23.0/.readthedocs.yaml0000664000175000017500000000147514646203155020366 0ustar carstencarsten# .readthedocs.yaml # Read the Docs configuration file # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details # Required version: 2 # Set the OS, Python version and other tools you might need build: os: ubuntu-22.04 tools: python: "3.11" # You can also specify other tool versions: # nodejs: "19" # rust: "1.64" # golang: "1.19" # Build documentation in the "docs/" directory with Sphinx sphinx: configuration: py/docs/source/conf.py # Optionally build your docs in additional formats such as PDF and ePub # formats: # - pdf # - epub # Optional but recommended, declare the Python requirements required # to build your documentation # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html python: install: - requirements: py/docs/requirements.txt selenium-selenium-4.23.0/MANIFEST.in0000664000175000017500000000176314646203155016675 0ustar carstencarstenprune * recursive-include selenium/webdriver *.py recursive-include selenium/webdriver/common *.py recursive-include selenium/webdriver/common/actions *.py recursive-include selenium/webdriver/common/html5 *.py recursive-include selenium/common *.py recursive-include selenium/webdriver/chromium *.py recursive-include selenium/webdriver/chrome *.py recursive-include selenium/webdriver/phantomjs *.py recursive-include selenium/webdriver/firefox *.py *.xpi *.json recursive-include selenium/webdriver/ie *.py recursive-include selenium/webdriver/edge *.py recursive-include selenium/webdriver/remote *.py *.js recursive-include selenium/webdriver/support *.py include selenium/selenium.py include selenium/__init__.py include selenium/py.typed include selenium/webdriver/common/linux/selenium-manager include selenium/webdriver/common/macos/selenium-manager include selenium/webdriver/common/windows/selenium-manager.exe include CHANGES include README.rst include LICENSE recursive-include selenium.egg-info * selenium-selenium-4.23.0/requirements.txt0000664000175000017500000000116214646203155020414 0ustar carstencarstenasync-generator==1.10 attrs==23.2.0 certifi==2023.11.17 cffi==1.16.0 cryptography==42.0.7 debugpy==1.8.1 h11==0.14.0 idna==3.7 importlib-metadata==6.8.0 inflection==0.5.1 iniconfig==2.0.0 more-itertools==10.1.0 multidict==6.0.5 outcome==1.3.0 packaging==23.2 pluggy==1.3.0 py==1.11.0 pycparser==2.21 pyOpenSSL==22.0.0 pyparsing==3.1.2 PySocks==1.7.1 pytest==7.4.4 pytest-instafail==0.5.0 pytest-mock==3.12.0 pytest-trio==0.8.0 sniffio==1.3.1 sortedcontainers==2.4.0 toml==0.10.2 trio>=0.20.2 trio-websocket==0.9.2 twine==4.0.2 typing_extensions==4.9.0 urllib3[socks]==2.0.7 websocket-client==1.8.0 wsproto==1.2.0 zipp==3.17.0 selenium-selenium-4.23.0/generate.py0000664000175000017500000010471714646203155017306 0ustar carstencarsten# The MIT License(MIT) # # Copyright(c) 2018 Hyperion Gray # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # This is a copy of https://github.com/HyperionGray/python-chrome-devtools-protocol/blob/master/generator/generate.py # The license above is theirs and MUST be preserved. # flake8: noqa import builtins from dataclasses import dataclass from enum import Enum import itertools import json import logging import operator import os from pathlib import Path import re from textwrap import dedent, indent as tw_indent import typing import inflection # type: ignore log_level = getattr(logging, os.environ.get('LOG_LEVEL', 'warning').upper()) logging.basicConfig(level=log_level) logger = logging.getLogger('generate') SHARED_HEADER = '''# DO NOT EDIT THIS FILE! # # This file is generated from the CDP specification. If you need to make # changes, edit the generator and regenerate all of the modules.''' INIT_HEADER = '''{} '''.format(SHARED_HEADER) MODULE_HEADER = '''{} # # CDP domain: {{}}{{}} from __future__ import annotations from .util import event_class, T_JSON_DICT from dataclasses import dataclass import enum import typing '''.format(SHARED_HEADER) current_version = '' UTIL_PY = """ import typing T_JSON_DICT = typing.Dict[str, typing.Any] _event_parsers = dict() def event_class(method): ''' A decorator that registers a class as an event class. ''' def decorate(cls): _event_parsers[method] = cls cls.event_class = method return cls return decorate def parse_json_event(json: T_JSON_DICT) -> typing.Any: ''' Parse a JSON dictionary into a CDP event. ''' return _event_parsers[json['method']].from_json(json['params']) """ def indent(s, n): ''' A shortcut for ``textwrap.indent`` that always uses spaces. ''' return tw_indent(s, n * ' ') BACKTICK_RE = re.compile(r'`([^`]+)`(\w+)?') def escape_backticks(docstr): ''' Escape backticks in a docstring by doubling them up. This is a little tricky because RST requires a non-letter character after the closing backticks, but some CDPs docs have things like "`AxNodeId`s". If we double the backticks in that string, then it won't be valid RST. The fix is to insert an apostrophe if an "s" trails the backticks. ''' def replace_one(match): if match.group(2) == 's': return f"``{match.group(1)}``'s" if match.group(2): # This case (some trailer other than "s") doesn't currently exist # in the CDP definitions, but it's here just to be safe. return f'``{match.group(1)}`` {match.group(2)}' return f'``{match.group(1)}``' # Sometimes pipes are used where backticks should have been used. docstr = docstr.replace('|', '`') return BACKTICK_RE.sub(replace_one, docstr) def inline_doc(description): ''' Generate an inline doc, e.g. ``#: This type is a ...`` ''' if not description: return '' description = escape_backticks(description) lines = [f'#: {l}' for l in description.split('\n')] return '\n'.join(lines) def docstring(description): ''' Generate a docstring from a description. ''' if not description: return '' description = escape_backticks(description) return dedent("'''\n{}\n'''").format(description) def is_builtin(name): ''' Return True if ``name`` would shadow a builtin. ''' try: getattr(builtins, name) return True except AttributeError: return False def snake_case(name): ''' Convert a camel case name to snake case. If the name would shadow a Python builtin, then append an underscore. ''' name = inflection.underscore(name) if is_builtin(name): name += '_' return name def ref_to_python(ref): ''' Convert a CDP ``$ref`` to the name of a Python type. For a dotted ref, the part before the dot is snake cased. ''' if '.' in ref: domain, subtype = ref.split('.') ref = f'{snake_case(domain)}.{subtype}' return f"{ref}" class CdpPrimitiveType(Enum): ''' All of the CDP types that map directly to a Python type. ''' boolean = 'bool' integer = 'int' number = 'float' object = 'dict' string = 'str' @classmethod def get_annotation(cls, cdp_type): ''' Return a type annotation for the CDP type. ''' if cdp_type == 'any': return 'typing.Any' return cls[cdp_type].value @classmethod def get_constructor(cls, cdp_type, val): ''' Return the code to construct a value for a given CDP type. ''' if cdp_type == 'any': return val cons = cls[cdp_type].value return f'{cons}({val})' @dataclass class CdpItems: ''' Represents the type of a repeated item. ''' type: str ref: str @classmethod def from_json(cls, type): ''' Generate code to instantiate an item from a JSON object. ''' return cls(type.get('type'), type.get('$ref')) @dataclass class CdpProperty: ''' A property belonging to a non-primitive CDP type. ''' name: str description: typing.Optional[str] type: typing.Optional[str] ref: typing.Optional[str] enum: typing.List[str] items: typing.Optional[CdpItems] optional: bool experimental: bool deprecated: bool @property def py_name(self): ''' Get this property's Python name. ''' return snake_case(self.name) @property def py_annotation(self): ''' This property's Python type annotation. ''' if self.items: if self.items.ref: py_ref = ref_to_python(self.items.ref) ann = f"typing.List[{py_ref}]" else: ann = 'typing.List[{}]'.format( CdpPrimitiveType.get_annotation(self.items.type)) else: if self.ref: py_ref = ref_to_python(self.ref) ann = py_ref else: ann = CdpPrimitiveType.get_annotation( typing.cast(str, self.type)) if self.optional: ann = f'typing.Optional[{ann}]' return ann @classmethod def from_json(cls, property): ''' Instantiate a CDP property from a JSON object. ''' return cls( property['name'], property.get('description'), property.get('type'), property.get('$ref'), property.get('enum'), CdpItems.from_json(property['items']) if 'items' in property else None, property.get('optional', False), property.get('experimental', False), property.get('deprecated', False), ) def generate_decl(self): ''' Generate the code that declares this property. ''' code = inline_doc(self.description) if code: code += '\n' code += f'{self.py_name}: {self.py_annotation}' if self.optional: code += ' = None' return code def generate_to_json(self, dict_, use_self=True): ''' Generate the code that exports this property to the specified JSON dict. ''' self_ref = 'self.' if use_self else '' assign = f"{dict_}['{self.name}'] = " if self.items: if self.items.ref: assign += f"[i.to_json() for i in {self_ref}{self.py_name}]" else: assign += f"[i for i in {self_ref}{self.py_name}]" else: if self.ref: assign += f"{self_ref}{self.py_name}.to_json()" else: assign += f"{self_ref}{self.py_name}" if self.optional: code = dedent(f'''\ if {self_ref}{self.py_name} is not None: {assign}''') else: code = assign return code def generate_from_json(self, dict_): ''' Generate the code that creates an instance from a JSON dict named ``dict_``. ''' if self.items: if self.items.ref: py_ref = ref_to_python(self.items.ref) expr = f"[{py_ref}.from_json(i) for i in {dict_}['{self.name}']]" expr else: cons = CdpPrimitiveType.get_constructor(self.items.type, 'i') expr = f"[{cons} for i in {dict_}['{self.name}']]" else: if self.ref: py_ref = ref_to_python(self.ref) expr = f"{py_ref}.from_json({dict_}['{self.name}'])" else: expr = CdpPrimitiveType.get_constructor(self.type, f"{dict_}['{self.name}']") if self.optional: expr = f"{expr} if '{self.name}' in {dict_} else None" return expr @dataclass class CdpType: ''' A top-level CDP type. ''' id: str description: typing.Optional[str] type: str items: typing.Optional[CdpItems] enum: typing.List[str] properties: typing.List[CdpProperty] @classmethod def from_json(cls, type_): ''' Instantiate a CDP type from a JSON object. ''' return cls( type_['id'], type_.get('description'), type_['type'], CdpItems.from_json(type_['items']) if 'items' in type_ else None, type_.get('enum'), [CdpProperty.from_json(p) for p in type_.get('properties', [])], ) def generate_code(self): ''' Generate Python code for this type. ''' logger.debug('Generating type %s: %s', self.id, self.type) if self.enum: return self.generate_enum_code() if self.properties: return self.generate_class_code() return self.generate_primitive_code() def generate_primitive_code(self): ''' Generate code for a primitive type. ''' if self.items: if self.items.ref: nested_type = ref_to_python(self.items.ref) else: nested_type = CdpPrimitiveType.get_annotation(self.items.type) py_type = f'typing.List[{nested_type}]' superclass = 'list' else: # A primitive type cannot have a ref, so there is no branch here. py_type = CdpPrimitiveType.get_annotation(self.type) superclass = py_type code = f'class {self.id}({superclass}):\n' doc = docstring(self.description) if doc: code += indent(doc, 4) + '\n' def_to_json = dedent(f'''\ def to_json(self) -> {py_type}: return self''') code += indent(def_to_json, 4) def_from_json = dedent(f'''\ @classmethod def from_json(cls, json: {py_type}) -> {self.id}: return cls(json)''') code += '\n\n' + indent(def_from_json, 4) def_repr = dedent(f'''\ def __repr__(self): return '{self.id}({{}})'.format(super().__repr__())''') code += '\n\n' + indent(def_repr, 4) return code def generate_enum_code(self): ''' Generate an "enum" type. Enums are handled by making a python class that contains only class members. Each class member is upper snaked case, e.g. ``MyTypeClass.MY_ENUM_VALUE`` and is assigned a string value from the CDP metadata. ''' def_to_json = dedent('''\ def to_json(self): return self.value''') def_from_json = dedent('''\ @classmethod def from_json(cls, json): return cls(json)''') code = f'class {self.id}(enum.Enum):\n' doc = docstring(self.description) if doc: code += indent(doc, 4) + '\n' for enum_member in self.enum: snake_name = snake_case(enum_member).upper() enum_code = f'{snake_name} = "{enum_member}"\n' code += indent(enum_code, 4) code += '\n' + indent(def_to_json, 4) code += '\n\n' + indent(def_from_json, 4) return code def generate_class_code(self): ''' Generate a class type. Top-level types that are defined as a CDP ``object`` are turned into Python dataclasses. ''' # children = set() code = dedent(f'''\ @dataclass class {self.id}:\n''') doc = docstring(self.description) if doc: code += indent(doc, 4) + '\n' # Emit property declarations. These are sorted so that optional # properties come after required properties, which is required to make # the dataclass constructor work. props = list(self.properties) props.sort(key=operator.attrgetter('optional')) code += '\n\n'.join(indent(p.generate_decl(), 4) for p in props) code += '\n\n' # Emit to_json() method. The properties are sorted in the same order as # above for readability. def_to_json = dedent('''\ def to_json(self): json = dict() ''') assigns = (p.generate_to_json(dict_='json') for p in props) def_to_json += indent('\n'.join(assigns), 4) def_to_json += '\n' def_to_json += indent('return json', 4) code += indent(def_to_json, 4) + '\n\n' # Emit from_json() method. The properties are sorted in the same order # as above for readability. def_from_json = dedent('''\ @classmethod def from_json(cls, json): return cls( ''') from_jsons = [] for p in props: from_json = p.generate_from_json(dict_='json') from_jsons.append(f'{p.py_name}={from_json},') def_from_json += indent('\n'.join(from_jsons), 8) def_from_json += '\n' def_from_json += indent(')', 4) code += indent(def_from_json, 4) return code def get_refs(self): ''' Return all refs for this type. ''' refs = set() if self.enum: # Enum types don't have refs. pass elif self.properties: # Enumerate refs for a class type. for prop in self.properties: if prop.items and prop.items.ref: refs.add(prop.items.ref) elif prop.ref: refs.add(prop.ref) else: # A primitive type can't have a direct ref, but it can have an items # which contains a ref. if self.items and self.items.ref: refs.add(self.items.ref) return refs class CdpParameter(CdpProperty): ''' A parameter to a CDP command. ''' def generate_code(self): ''' Generate the code for a parameter in a function call. ''' if self.items: if self.items.ref: nested_type = ref_to_python(self.items.ref) py_type = f"typing.List[{nested_type}]" else: nested_type = CdpPrimitiveType.get_annotation(self.items.type) py_type = f'typing.List[{nested_type}]' else: if self.ref: py_type = f"{ref_to_python(self.ref)}" else: py_type = CdpPrimitiveType.get_annotation( typing.cast(str, self.type)) if self.optional: py_type = f'typing.Optional[{py_type}]' code = f"{self.py_name}: {py_type}" if self.optional: code += ' = None' return code def generate_decl(self): ''' Generate the declaration for this parameter. ''' if self.description: code = inline_doc(self.description) code += '\n' else: code = '' code += f'{self.py_name}: {self.py_annotation}' return code def generate_doc(self): ''' Generate the docstring for this parameter. ''' doc = f':param {self.py_name}:' if self.experimental: doc += ' **(EXPERIMENTAL)**' if self.optional: doc += ' *(Optional)*' if self.description: desc = self.description.replace('`', '``').replace('\n', ' ') doc += f' {desc}' return doc def generate_from_json(self, dict_): ''' Generate the code to instantiate this parameter from a JSON dict. ''' code = super().generate_from_json(dict_) return f'{self.py_name}={code}' class CdpReturn(CdpProperty): ''' A return value from a CDP command. ''' @property def py_annotation(self): ''' Return the Python type annotation for this return. ''' if self.items: if self.items.ref: py_ref = ref_to_python(self.items.ref) ann = f"typing.List[{py_ref}]" else: py_type = CdpPrimitiveType.get_annotation(self.items.type) ann = f'typing.List[{py_type}]' else: if self.ref: py_ref = ref_to_python(self.ref) ann = f"{py_ref}" else: ann = CdpPrimitiveType.get_annotation(self.type) if self.optional: ann = f'typing.Optional[{ann}]' return ann def generate_doc(self): ''' Generate the docstring for this return. ''' if self.description: doc = self.description.replace('\n', ' ') if self.optional: doc = f'*(Optional)* {doc}' else: doc = '' return doc def generate_return(self, dict_): ''' Generate code for returning this value. ''' return super().generate_from_json(dict_) @dataclass class CdpCommand: ''' A CDP command. ''' name: str description: str experimental: bool deprecated: bool parameters: typing.List[CdpParameter] returns: typing.List[CdpReturn] domain: str @property def py_name(self): ''' Get a Python name for this command. ''' return snake_case(self.name) @classmethod def from_json(cls, command, domain) -> 'CdpCommand': ''' Instantiate a CDP command from a JSON object. ''' parameters = command.get('parameters', []) returns = command.get('returns', []) return cls( command['name'], command.get('description'), command.get('experimental', False), command.get('deprecated', False), [typing.cast(CdpParameter, CdpParameter.from_json(p)) for p in parameters], [typing.cast(CdpReturn, CdpReturn.from_json(r)) for r in returns], domain, ) def generate_code(self): ''' Generate code for a CDP command. ''' global current_version # Generate the function header if len(self.returns) == 0: ret_type = 'None' elif len(self.returns) == 1: ret_type = self.returns[0].py_annotation else: nested_types = ', '.join(r.py_annotation for r in self.returns) ret_type = f'typing.Tuple[{nested_types}]' ret_type = f"typing.Generator[T_JSON_DICT,T_JSON_DICT,{ret_type}]" code = '' code += f'def {self.py_name}(' ret = f') -> {ret_type}:\n' if self.parameters: params = [p.generate_code() for p in self.parameters] optional = False clean_params = [] for para in params: if "= None" in para: optional = True if optional and "= None" not in para: para += ' = None' clean_params.append(para) code += '\n' code += indent( ',\n'.join(clean_params), 8) code += '\n' code += indent(ret, 4) else: code += ret # Generate the docstring doc = '' if self.description: doc = self.description if self.experimental: doc += '\n\n**EXPERIMENTAL**' if self.parameters and doc: doc += '\n\n' elif not self.parameters and self.returns: doc += '\n' doc += '\n'.join(p.generate_doc() for p in self.parameters) if len(self.returns) == 1: doc += '\n' ret_doc = self.returns[0].generate_doc() doc += f':returns: {ret_doc}' elif len(self.returns) > 1: doc += '\n' doc += ':returns: A tuple with the following items:\n\n' ret_docs = '\n'.join(f'{i}. **{r.name}** - {r.generate_doc()}' for i, r in enumerate(self.returns)) doc += indent(ret_docs, 4) if doc: code += indent(docstring(doc), 4) # Generate the function body if self.parameters: code += '\n' code += indent('params: T_JSON_DICT = dict()', 4) code += '\n' assigns = (p.generate_to_json(dict_='params', use_self=False) for p in self.parameters) code += indent('\n'.join(assigns), 4) code += '\n' code += indent('cmd_dict: T_JSON_DICT = {\n', 4) code += indent(f"'method': '{self.domain}.{self.name}',\n", 8) if self.parameters: code += indent("'params': params,\n", 8) code += indent('}\n', 4) code += indent('json = yield cmd_dict', 4) if len(self.returns) == 0: pass elif len(self.returns) == 1: ret = self.returns[0].generate_return(dict_='json') code += indent(f'\nreturn {ret}', 4) else: ret = '\nreturn (\n' expr = ',\n'.join(r.generate_return(dict_='json') for r in self.returns) ret += indent(expr, 4) ret += '\n)' code += indent(ret, 4) return code def get_refs(self): ''' Get all refs for this command. ''' refs = set() for type_ in itertools.chain(self.parameters, self.returns): if type_.items and type_.items.ref: refs.add(type_.items.ref) elif type_.ref: refs.add(type_.ref) return refs @dataclass class CdpEvent: ''' A CDP event object. ''' name: str description: typing.Optional[str] deprecated: bool experimental: bool parameters: typing.List[CdpParameter] domain: str @property def py_name(self): ''' Return the Python class name for this event. ''' return inflection.camelize(self.name, uppercase_first_letter=True) @classmethod def from_json(cls, json: dict, domain: str): ''' Create a new CDP event instance from a JSON dict. ''' return cls( json['name'], json.get('description'), json.get('deprecated', False), json.get('experimental', False), [typing.cast(CdpParameter, CdpParameter.from_json(p)) for p in json.get('parameters', [])], domain ) def generate_code(self): ''' Generate code for a CDP event. ''' global current_version code = dedent(f'''\ @event_class('{self.domain}.{self.name}') @dataclass class {self.py_name}:''') code += '\n' desc = '' if self.description or self.experimental: if self.experimental: desc += '**EXPERIMENTAL**\n\n' if self.description: desc += self.description code += indent(docstring(desc), 4) code += '\n' code += indent( '\n'.join(p.generate_decl() for p in self.parameters), 4) code += '\n\n' def_from_json = dedent(f'''\ @classmethod def from_json(cls, json: T_JSON_DICT) -> {self.py_name}: return cls( ''') code += indent(def_from_json, 4) from_json = ',\n'.join(p.generate_from_json(dict_='json') for p in self.parameters) code += indent(from_json, 12) code += '\n' code += indent(')', 8) return code def get_refs(self): ''' Get all refs for this event. ''' refs = set() for param in self.parameters: if param.items and param.items.ref: refs.add(param.items.ref) elif param.ref: refs.add(param.ref) return refs @dataclass class CdpDomain: ''' A CDP domain contains metadata, types, commands, and events. ''' domain: str description: typing.Optional[str] experimental: bool dependencies: typing.List[str] types: typing.List[CdpType] commands: typing.List[CdpCommand] events: typing.List[CdpEvent] @property def module(self): ''' The name of the Python module for this CDP domain. ''' return snake_case(self.domain) @classmethod def from_json(cls, domain: dict): ''' Instantiate a CDP domain from a JSON object. ''' types = domain.get('types', []) commands = domain.get('commands', []) events = domain.get('events', []) domain_name = domain['domain'] return cls( domain_name, domain.get('description'), domain.get('experimental', False), domain.get('dependencies', []), [CdpType.from_json(type) for type in types], [CdpCommand.from_json(command, domain_name) for command in commands], [CdpEvent.from_json(event, domain_name) for event in events] ) def generate_code(self): ''' Generate the Python module code for a given CDP domain. ''' exp = ' (experimental)' if self.experimental else '' code = MODULE_HEADER.format(self.domain, exp) import_code = self.generate_imports() if import_code: code += import_code code += '\n\n' code += '\n' item_iter_t = typing.Union[CdpEvent, CdpCommand, CdpType] item_iter: typing.Iterator[item_iter_t] = itertools.chain( iter(self.types), iter(self.commands), iter(self.events), ) code += '\n\n\n'.join(item.generate_code() for item in item_iter) code += '\n' return code def generate_imports(self): ''' Determine which modules this module depends on and emit the code to import those modules. Notice that CDP defines a ``dependencies`` field for each domain, but these dependencies are a subset of the modules that we actually need to import to make our Python code work correctly and type safe. So we ignore the CDP's declared dependencies and compute them ourselves. ''' refs = set() for type_ in self.types: refs |= type_.get_refs() for command in self.commands: refs |= command.get_refs() for event in self.events: refs |= event.get_refs() dependencies = set() for ref in refs: try: domain, _ = ref.split('.') except ValueError: continue if domain != self.domain: dependencies.add(snake_case(domain)) code = '\n'.join(f'from . import {d}' for d in sorted(dependencies)) return code def generate_sphinx(self): ''' Generate a Sphinx document for this domain. ''' docs = self.domain + '\n' docs += '=' * len(self.domain) + '\n\n' if self.description: docs += f'{self.description}\n\n' if self.experimental: docs += '*This CDP domain is experimental.*\n\n' docs += f'.. module:: cdp.{self.module}\n\n' docs += '* Types_\n* Commands_\n* Events_\n\n' docs += 'Types\n-----\n\n' if self.types: docs += dedent('''\ Generally, you do not need to instantiate CDP types yourself. Instead, the API creates objects for you as return values from commands, and then you can use those objects as arguments to other commands. ''') else: docs += '*There are no types in this module.*\n' for type in self.types: docs += f'\n.. autoclass:: {type.id}\n' docs += ' :members:\n' docs += ' :undoc-members:\n' docs += ' :exclude-members: from_json, to_json\n' docs += '\nCommands\n--------\n\n' if self.commands: docs += dedent('''\ Each command is a generator function. The return type ``Generator[x, y, z]`` indicates that the generator *yields* arguments of type ``x``, it must be resumed with an argument of type ``y``, and it returns type ``z``. In this library, types ``x`` and ``y`` are the same for all commands, and ``z`` is the return type you should pay attention to. For more information, see :ref:`Getting Started: Commands `. ''') else: docs += '*There are no types in this module.*\n' for command in sorted(self.commands, key=operator.attrgetter('py_name')): docs += f'\n.. autofunction:: {command.py_name}\n' docs += '\nEvents\n------\n\n' if self.events: docs += dedent('''\ Generally, you do not need to instantiate CDP events yourself. Instead, the API creates events for you and then you use the event\'s attributes. ''') else: docs += '*There are no events in this module.*\n' for event in self.events: docs += f'\n.. autoclass:: {event.py_name}\n' docs += ' :members:\n' docs += ' :undoc-members:\n' docs += ' :exclude-members: from_json, to_json\n' return docs def parse(json_path, output_path): ''' Parse JSON protocol description and return domain objects. :param Path json_path: path to a JSON CDP schema :param Path output_path: a directory path to create the modules in :returns: a list of CDP domain objects ''' global current_version with open(json_path, encoding="utf-8") as json_file: schema = json.load(json_file) version = schema['version'] assert (version['major'], version['minor']) == ('1', '3') current_version = f'{version["major"]}.{version["minor"]}' domains = [] for domain in schema['domains']: domains.append(CdpDomain.from_json(domain)) return domains def generate_init(init_path, domains): ''' Generate an ``__init__.py`` that exports the specified modules. :param Path init_path: a file path to create the init file in :param list[tuple] modules: a list of modules each represented as tuples of (name, list_of_exported_symbols) ''' with open(init_path, "w", encoding="utf-8") as init_file: init_file.write(INIT_HEADER) for domain in domains: init_file.write(f'from . import {domain.module}\n') init_file.write('from . import util\n\n') def generate_docs(docs_path, domains): ''' Generate Sphinx documents for each domain. ''' logger.info('Generating Sphinx documents') # Remove generated documents for subpath in docs_path.iterdir(): subpath.unlink() # Generate document for each domain for domain in domains: doc = docs_path / f'{domain.module}.rst' with doc.open('w') as f: f.write(domain.generate_sphinx()) def main(browser_protocol_path, js_protocol_path, output_path): ''' Main entry point. ''' output_path = Path(output_path).resolve() json_paths = [ browser_protocol_path, js_protocol_path, ] # Generate util.py util_path = output_path / "util.py" with util_path.open('w') as util_file: util_file.write(UTIL_PY) # Remove generated code for subpath in output_path.iterdir(): if subpath.is_file() and subpath.name not in ('py.typed', 'util.py'): subpath.unlink() # Parse domains domains = [] for json_path in json_paths: logger.info('Parsing JSON file %s', json_path) domains.extend(parse(json_path, output_path)) domains.sort(key=operator.attrgetter('domain')) # Patch up CDP errors. It's easier to patch that here than it is to modify # the generator code. # 1. DOM includes an erroneous $ref that refers to itself. # 2. Page includes an event with an extraneous backtick in the description. for domain in domains: if domain.domain == 'DOM': for cmd in domain.commands: if cmd.name == 'resolveNode': # Patch 1 cmd.parameters[1].ref = 'BackendNodeId' elif domain.domain == 'Page': for event in domain.events: if event.name == 'screencastVisibilityChanged': # Patch 2 event.description = event.description.replace('`', '') for domain in domains: logger.info('Generating module: %s → %s.py', domain.domain, domain.module) module_path = output_path / f'{domain.module}.py' with module_path.open('w') as module_file: module_file.write(domain.generate_code()) init_path = output_path / '__init__.py' generate_init(init_path, domains) # Not generating the docs as we don't want people to directly # Use the CDP APIs # docs_path = here.parent / 'docs' / 'api' # generate_docs(docs_path, domains) py_typed_path = output_path / 'py.typed' py_typed_path.touch() if __name__ == '__main__': import sys assert sys.version_info >= (3, 7), "To generate the CDP code requires python 3.7 or later" args = sys.argv[1:] main(*args) selenium-selenium-4.23.0/pnpm-lock.yaml0000664000175000017500000062307214646203155017726 0ustar carstencarstenlockfileVersion: '6.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false importers: .: {} javascript/grid-ui: dependencies: '@apollo/client': specifier: 3.10.4 version: 3.10.4(@types/react@18.2.72)(graphql@16.8.1)(react-dom@18.2.0)(react@18.2.0) '@emotion/react': specifier: 11.11.4 version: 11.11.4(@types/react@18.2.72)(react@18.2.0) '@emotion/styled': specifier: 11.11.5 version: 11.11.5(@emotion/react@11.11.4)(@types/react@18.2.72)(react@18.2.0) '@mui/icons-material': specifier: 5.15.18 version: 5.15.18(@mui/material@5.15.18)(@types/react@18.2.72)(react@18.2.0) '@mui/material': specifier: 5.15.18 version: 5.15.18(@emotion/react@11.11.4)(@emotion/styled@11.11.5)(@types/react@18.2.72)(react-dom@18.2.0)(react@18.2.0) '@novnc/novnc': specifier: 1.4.0 version: 1.4.0 '@types/jest': specifier: 29.5.12 version: 29.5.12 '@types/node': specifier: 20.12.12 version: 20.12.12 '@types/react': specifier: 18.2.72 version: 18.2.72 '@types/react-dom': specifier: 18.2.22 version: 18.2.22 '@types/react-modal': specifier: 3.16.3 version: 3.16.3 '@types/react-router-dom': specifier: 5.3.3 version: 5.3.3 graphql: specifier: 16.8.1 version: 16.8.1 graphql.macro: specifier: 1.4.2 version: 1.4.2(@babel/core@7.24.7)(graphql@16.8.1) path-browserify: specifier: 1.0.1 version: 1.0.1 pretty-ms: specifier: 9.0.0 version: 9.0.0 react: specifier: 18.2.0 version: 18.2.0 react-dom: specifier: 18.2.0 version: 18.2.0(react@18.2.0) react-modal: specifier: 3.16.1 version: 3.16.1(react-dom@18.2.0)(react@18.2.0) react-router-dom: specifier: 6.22.3 version: 6.22.3(react-dom@18.2.0)(react@18.2.0) source-map-explorer: specifier: 2.5.3 version: 2.5.3 devDependencies: '@babel/preset-react': specifier: 7.24.7 version: 7.24.7(@babel/core@7.24.7) '@testing-library/jest-dom': specifier: 6.4.5 version: 6.4.5(@types/jest@29.5.12) '@testing-library/react': specifier: 14.3.1 version: 14.3.1(react-dom@18.2.0)(react@18.2.0) '@testing-library/user-event': specifier: 14.5.2 version: 14.5.2(@testing-library/dom@10.2.0) esbuild: specifier: 0.19.12 version: 0.19.12 ts-standard: specifier: 12.0.2 version: 12.0.2(typescript@5.4.5) typescript: specifier: 5.4.5 version: 5.4.5 javascript/node/selenium-webdriver: dependencies: '@bazel/runfiles': specifier: ^5.8.1 version: 5.8.1 jszip: specifier: ^3.10.1 version: 3.10.1 tmp: specifier: ^0.2.3 version: 0.2.3 ws: specifier: ^8.17.1 version: 8.17.1 devDependencies: '@eslint/js': specifier: ^9.5.0 version: 9.5.0 clean-jsdoc-theme: specifier: ^4.3.0 version: 4.3.0(jsdoc@4.0.3) eslint: specifier: ^9.5.0 version: 9.5.0(supports-color@9.4.0) eslint-config-prettier: specifier: ^9.1.0 version: 9.1.0(eslint@9.5.0) eslint-plugin-mocha: specifier: ^10.4.3 version: 10.4.3(eslint@9.5.0) eslint-plugin-n: specifier: ^17.9.0 version: 17.9.0(eslint@9.5.0) eslint-plugin-no-only-tests: specifier: ^3.1.0 version: 3.1.0 eslint-plugin-prettier: specifier: ^5.1.3 version: 5.1.3(eslint-config-prettier@9.1.0)(eslint@9.5.0)(prettier@3.3.2) express: specifier: ^4.19.2 version: 4.19.2(supports-color@9.4.0) globals: specifier: ^15.6.0 version: 15.6.0 has-flag: specifier: ^4.0.0 version: 4.0.0 jsdoc: specifier: ^4.0.3 version: 4.0.3 mocha: specifier: ^10.5.1 version: 10.5.1 mocha-junit-reporter: specifier: ^2.2.1 version: 2.2.1(mocha@10.5.1)(supports-color@9.4.0) multer: specifier: 1.4.5-lts.1 version: 1.4.5-lts.1 prettier: specifier: ^3.3.2 version: 3.3.2 serve-index: specifier: ^1.9.1 version: 1.9.1(supports-color@9.4.0) sinon: specifier: ^17.0.1 version: 17.0.1 supports-color: specifier: ^9.4.0 version: 9.4.0 packages: /@adobe/css-tools@4.4.0: resolution: {integrity: sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==} dev: true /@ampproject/remapping@2.3.0: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} dependencies: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 /@apollo/client@3.10.4(@types/react@18.2.72)(graphql@16.8.1)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-51gk0xOwN6Ls1EbTG5svFva1kdm2APHYTzmFhaAdvUQoJFDxfc0UwQgDxGptzH84vkPlo1qunY1FuboyF9LI3Q==} peerDependencies: graphql: ^15.0.0 || ^16.0.0 graphql-ws: ^5.5.5 react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 subscriptions-transport-ws: ^0.9.0 || ^0.11.0 peerDependenciesMeta: graphql-ws: optional: true react: optional: true react-dom: optional: true subscriptions-transport-ws: optional: true dependencies: '@graphql-typed-document-node/core': 3.2.0(graphql@16.8.1) '@wry/caches': 1.0.1 '@wry/equality': 0.5.7 '@wry/trie': 0.5.0 graphql: 16.8.1 graphql-tag: 2.12.6(graphql@16.8.1) hoist-non-react-statics: 3.3.2 optimism: 0.18.0 prop-types: 15.8.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) rehackt: 0.1.0(@types/react@18.2.72)(react@18.2.0) response-iterator: 0.2.6 symbol-observable: 4.0.0 ts-invariant: 0.10.3 tslib: 2.6.3 zen-observable-ts: 1.2.5 transitivePeerDependencies: - '@types/react' dev: false /@babel/code-frame@7.24.7: resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} engines: {node: '>=6.9.0'} dependencies: '@babel/highlight': 7.24.7 picocolors: 1.0.1 /@babel/compat-data@7.24.7: resolution: {integrity: sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==} engines: {node: '>=6.9.0'} /@babel/core@7.24.7: resolution: {integrity: sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==} engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.3.0 '@babel/code-frame': 7.24.7 '@babel/generator': 7.24.7 '@babel/helper-compilation-targets': 7.24.7 '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7) '@babel/helpers': 7.24.7 '@babel/parser': 7.24.7 '@babel/template': 7.24.7 '@babel/traverse': 7.24.7 '@babel/types': 7.24.7 convert-source-map: 2.0.0 debug: 4.3.5(supports-color@9.4.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 transitivePeerDependencies: - supports-color /@babel/generator@7.24.7: resolution: {integrity: sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.7 '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 /@babel/helper-annotate-as-pure@7.24.7: resolution: {integrity: sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.7 dev: true /@babel/helper-compilation-targets@7.24.7: resolution: {integrity: sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==} engines: {node: '>=6.9.0'} dependencies: '@babel/compat-data': 7.24.7 '@babel/helper-validator-option': 7.24.7 browserslist: 4.23.1 lru-cache: 5.1.1 semver: 6.3.1 /@babel/helper-environment-visitor@7.24.7: resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.7 /@babel/helper-function-name@7.24.7: resolution: {integrity: sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==} engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.24.7 '@babel/types': 7.24.7 /@babel/helper-hoist-variables@7.24.7: resolution: {integrity: sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.7 /@babel/helper-module-imports@7.24.7: resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==} engines: {node: '>=6.9.0'} dependencies: '@babel/traverse': 7.24.7 '@babel/types': 7.24.7 transitivePeerDependencies: - supports-color /@babel/helper-module-transforms@7.24.7(@babel/core@7.24.7): resolution: {integrity: sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.24.7 '@babel/helper-environment-visitor': 7.24.7 '@babel/helper-module-imports': 7.24.7 '@babel/helper-simple-access': 7.24.7 '@babel/helper-split-export-declaration': 7.24.7 '@babel/helper-validator-identifier': 7.24.7 transitivePeerDependencies: - supports-color /@babel/helper-plugin-utils@7.24.7: resolution: {integrity: sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==} engines: {node: '>=6.9.0'} dev: true /@babel/helper-simple-access@7.24.7: resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==} engines: {node: '>=6.9.0'} dependencies: '@babel/traverse': 7.24.7 '@babel/types': 7.24.7 transitivePeerDependencies: - supports-color /@babel/helper-split-export-declaration@7.24.7: resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.7 /@babel/helper-string-parser@7.24.7: resolution: {integrity: sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==} engines: {node: '>=6.9.0'} /@babel/helper-validator-identifier@7.24.7: resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} engines: {node: '>=6.9.0'} /@babel/helper-validator-option@7.24.7: resolution: {integrity: sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==} engines: {node: '>=6.9.0'} /@babel/helpers@7.24.7: resolution: {integrity: sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==} engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.24.7 '@babel/types': 7.24.7 /@babel/highlight@7.24.7: resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-validator-identifier': 7.24.7 chalk: 2.4.2 js-tokens: 4.0.0 picocolors: 1.0.1 /@babel/parser@7.24.7: resolution: {integrity: sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==} engines: {node: '>=6.0.0'} hasBin: true dependencies: '@babel/types': 7.24.7 /@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.24.7): resolution: {integrity: sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.7 '@babel/helper-plugin-utils': 7.24.7 dev: true /@babel/plugin-transform-react-display-name@7.24.7(@babel/core@7.24.7): resolution: {integrity: sha512-H/Snz9PFxKsS1JLI4dJLtnJgCJRoo0AUm3chP6NYr+9En1JMKloheEiLIhlp5MDVznWo+H3AAC1Mc8lmUEpsgg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.7 '@babel/helper-plugin-utils': 7.24.7 dev: true /@babel/plugin-transform-react-jsx-development@7.24.7(@babel/core@7.24.7): resolution: {integrity: sha512-QG9EnzoGn+Qar7rxuW+ZOsbWOt56FvvI93xInqsZDC5fsekx1AlIO4KIJ5M+D0p0SqSH156EpmZyXq630B8OlQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.7 '@babel/plugin-transform-react-jsx': 7.24.7(@babel/core@7.24.7) transitivePeerDependencies: - supports-color dev: true /@babel/plugin-transform-react-jsx@7.24.7(@babel/core@7.24.7): resolution: {integrity: sha512-+Dj06GDZEFRYvclU6k4bme55GKBEWUmByM/eoKuqg4zTNQHiApWRhQph5fxQB2wAEFvRzL1tOEj1RJ19wJrhoA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.7 '@babel/helper-annotate-as-pure': 7.24.7 '@babel/helper-module-imports': 7.24.7 '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.24.7) '@babel/types': 7.24.7 transitivePeerDependencies: - supports-color dev: true /@babel/plugin-transform-react-pure-annotations@7.24.7(@babel/core@7.24.7): resolution: {integrity: sha512-PLgBVk3fzbmEjBJ/u8kFzOqS9tUeDjiaWud/rRym/yjCo/M9cASPlnrd2ZmmZpQT40fOOrvR8jh+n8jikrOhNA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.7 '@babel/helper-annotate-as-pure': 7.24.7 '@babel/helper-plugin-utils': 7.24.7 dev: true /@babel/preset-react@7.24.7(@babel/core@7.24.7): resolution: {integrity: sha512-AAH4lEkpmzFWrGVlHaxJB7RLH21uPQ9+He+eFLWHmF9IuFQVugz8eAsamaW0DXRrTfco5zj1wWtpdcXJUOfsag==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.7 '@babel/helper-plugin-utils': 7.24.7 '@babel/helper-validator-option': 7.24.7 '@babel/plugin-transform-react-display-name': 7.24.7(@babel/core@7.24.7) '@babel/plugin-transform-react-jsx': 7.24.7(@babel/core@7.24.7) '@babel/plugin-transform-react-jsx-development': 7.24.7(@babel/core@7.24.7) '@babel/plugin-transform-react-pure-annotations': 7.24.7(@babel/core@7.24.7) transitivePeerDependencies: - supports-color dev: true /@babel/runtime@7.24.7: resolution: {integrity: sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.1 /@babel/template@7.24.7: resolution: {integrity: sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==} engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.24.7 '@babel/parser': 7.24.7 '@babel/types': 7.24.7 /@babel/traverse@7.24.7: resolution: {integrity: sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==} engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.24.7 '@babel/generator': 7.24.7 '@babel/helper-environment-visitor': 7.24.7 '@babel/helper-function-name': 7.24.7 '@babel/helper-hoist-variables': 7.24.7 '@babel/helper-split-export-declaration': 7.24.7 '@babel/parser': 7.24.7 '@babel/types': 7.24.7 debug: 4.3.5(supports-color@9.4.0) globals: 11.12.0 transitivePeerDependencies: - supports-color /@babel/types@7.24.7: resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-string-parser': 7.24.7 '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 /@bazel/runfiles@5.8.1: resolution: {integrity: sha512-NDdfpdQ6rZlylgv++iMn5FkObC/QlBQvipinGLSOguTYpRywmieOyJ29XHvUilspwTFSILWpoE9CqMGkHXug1g==} dev: false /@emotion/babel-plugin@11.11.0: resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==} dependencies: '@babel/helper-module-imports': 7.24.7 '@babel/runtime': 7.24.7 '@emotion/hash': 0.9.1 '@emotion/memoize': 0.8.1 '@emotion/serialize': 1.1.4 babel-plugin-macros: 3.1.0 convert-source-map: 1.9.0 escape-string-regexp: 4.0.0 find-root: 1.1.0 source-map: 0.5.7 stylis: 4.2.0 transitivePeerDependencies: - supports-color dev: false /@emotion/cache@11.11.0: resolution: {integrity: sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==} dependencies: '@emotion/memoize': 0.8.1 '@emotion/sheet': 1.2.2 '@emotion/utils': 1.2.1 '@emotion/weak-memoize': 0.3.1 stylis: 4.2.0 dev: false /@emotion/hash@0.9.1: resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==} dev: false /@emotion/is-prop-valid@1.2.2: resolution: {integrity: sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==} dependencies: '@emotion/memoize': 0.8.1 dev: false /@emotion/memoize@0.8.1: resolution: {integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==} dev: false /@emotion/react@11.11.4(@types/react@18.2.72)(react@18.2.0): resolution: {integrity: sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==} peerDependencies: '@types/react': '*' react: '>=16.8.0' peerDependenciesMeta: '@types/react': optional: true dependencies: '@babel/runtime': 7.24.7 '@emotion/babel-plugin': 11.11.0 '@emotion/cache': 11.11.0 '@emotion/serialize': 1.1.4 '@emotion/use-insertion-effect-with-fallbacks': 1.0.1(react@18.2.0) '@emotion/utils': 1.2.1 '@emotion/weak-memoize': 0.3.1 '@types/react': 18.2.72 hoist-non-react-statics: 3.3.2 react: 18.2.0 transitivePeerDependencies: - supports-color dev: false /@emotion/serialize@1.1.4: resolution: {integrity: sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ==} dependencies: '@emotion/hash': 0.9.1 '@emotion/memoize': 0.8.1 '@emotion/unitless': 0.8.1 '@emotion/utils': 1.2.1 csstype: 3.1.3 dev: false /@emotion/sheet@1.2.2: resolution: {integrity: sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==} dev: false /@emotion/styled@11.11.5(@emotion/react@11.11.4)(@types/react@18.2.72)(react@18.2.0): resolution: {integrity: sha512-/ZjjnaNKvuMPxcIiUkf/9SHoG4Q196DRl1w82hQ3WCsjo1IUR8uaGWrC6a87CrYAW0Kb/pK7hk8BnLgLRi9KoQ==} peerDependencies: '@emotion/react': ^11.0.0-rc.0 '@types/react': '*' react: '>=16.8.0' peerDependenciesMeta: '@types/react': optional: true dependencies: '@babel/runtime': 7.24.7 '@emotion/babel-plugin': 11.11.0 '@emotion/is-prop-valid': 1.2.2 '@emotion/react': 11.11.4(@types/react@18.2.72)(react@18.2.0) '@emotion/serialize': 1.1.4 '@emotion/use-insertion-effect-with-fallbacks': 1.0.1(react@18.2.0) '@emotion/utils': 1.2.1 '@types/react': 18.2.72 react: 18.2.0 transitivePeerDependencies: - supports-color dev: false /@emotion/unitless@0.8.1: resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==} dev: false /@emotion/use-insertion-effect-with-fallbacks@1.0.1(react@18.2.0): resolution: {integrity: sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==} peerDependencies: react: '>=16.8.0' dependencies: react: 18.2.0 dev: false /@emotion/utils@1.2.1: resolution: {integrity: sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==} dev: false /@emotion/weak-memoize@0.3.1: resolution: {integrity: sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==} dev: false /@esbuild/aix-ppc64@0.19.12: resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} engines: {node: '>=12'} requiresBuild: true dev: true optional: true /@esbuild/android-arm64@0.19.12: resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} engines: {node: '>=12'} requiresBuild: true dev: true optional: true /@esbuild/android-arm@0.19.12: resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} engines: {node: '>=12'} requiresBuild: true dev: true optional: true /@esbuild/android-x64@0.19.12: resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} engines: {node: '>=12'} requiresBuild: true dev: true optional: true /@esbuild/darwin-arm64@0.19.12: resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} engines: {node: '>=12'} requiresBuild: true dev: true optional: true /@esbuild/darwin-x64@0.19.12: resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} engines: {node: '>=12'} requiresBuild: true dev: true optional: true /@esbuild/freebsd-arm64@0.19.12: resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} engines: {node: '>=12'} requiresBuild: true dev: true optional: true /@esbuild/freebsd-x64@0.19.12: resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} engines: {node: '>=12'} requiresBuild: true dev: true optional: true /@esbuild/linux-arm64@0.19.12: resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} engines: {node: '>=12'} requiresBuild: true dev: true optional: true /@esbuild/linux-arm@0.19.12: resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} engines: {node: '>=12'} requiresBuild: true dev: true optional: true /@esbuild/linux-ia32@0.19.12: resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} engines: {node: '>=12'} requiresBuild: true dev: true optional: true /@esbuild/linux-loong64@0.19.12: resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} engines: {node: '>=12'} requiresBuild: true dev: true optional: true /@esbuild/linux-mips64el@0.19.12: resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} engines: {node: '>=12'} requiresBuild: true dev: true optional: true /@esbuild/linux-ppc64@0.19.12: resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} engines: {node: '>=12'} requiresBuild: true dev: true optional: true /@esbuild/linux-riscv64@0.19.12: resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} engines: {node: '>=12'} requiresBuild: true dev: true optional: true /@esbuild/linux-s390x@0.19.12: resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} engines: {node: '>=12'} requiresBuild: true dev: true optional: true /@esbuild/linux-x64@0.19.12: resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} engines: {node: '>=12'} requiresBuild: true dev: true optional: true /@esbuild/netbsd-x64@0.19.12: resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} engines: {node: '>=12'} requiresBuild: true dev: true optional: true /@esbuild/openbsd-x64@0.19.12: resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} engines: {node: '>=12'} requiresBuild: true dev: true optional: true /@esbuild/sunos-x64@0.19.12: resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} engines: {node: '>=12'} requiresBuild: true dev: true optional: true /@esbuild/win32-arm64@0.19.12: resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} engines: {node: '>=12'} requiresBuild: true dev: true optional: true /@esbuild/win32-ia32@0.19.12: resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} engines: {node: '>=12'} requiresBuild: true dev: true optional: true /@esbuild/win32-x64@0.19.12: resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} engines: {node: '>=12'} requiresBuild: true dev: true optional: true /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: eslint: 8.57.0 eslint-visitor-keys: 3.4.3 dev: true /@eslint-community/eslint-utils@4.4.0(eslint@9.5.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: eslint: 9.5.0(supports-color@9.4.0) eslint-visitor-keys: 3.4.3 dev: true /@eslint-community/regexpp@4.10.1: resolution: {integrity: sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} dev: true /@eslint/config-array@0.16.0(supports-color@9.4.0): resolution: {integrity: sha512-/jmuSd74i4Czf1XXn7wGRWZCuyaUZ330NH1Bek0Pplatt4Sy1S5haN21SCLLdbeKslQ+S0wEJ+++v5YibSi+Lg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: '@eslint/object-schema': 2.1.4 debug: 4.3.5(supports-color@9.4.0) minimatch: 3.1.2 transitivePeerDependencies: - supports-color dev: true /@eslint/eslintrc@2.1.4: resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 debug: 4.3.5(supports-color@9.4.0) espree: 9.6.1 globals: 13.24.0 ignore: 5.3.1 import-fresh: 3.3.0 js-yaml: 4.1.0 minimatch: 3.1.2 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color dev: true /@eslint/eslintrc@3.1.0(supports-color@9.4.0): resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: ajv: 6.12.6 debug: 4.3.5(supports-color@9.4.0) espree: 10.1.0 globals: 14.0.0 ignore: 5.3.1 import-fresh: 3.3.0 js-yaml: 4.1.0 minimatch: 3.1.2 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color dev: true /@eslint/js@8.57.0: resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true /@eslint/js@9.5.0: resolution: {integrity: sha512-A7+AOT2ICkodvtsWnxZP4Xxk3NbZ3VMHd8oihydLRGrJgqqdEz1qSeEgXYyT/Cu8h1TWWsQRejIx48mtjZ5y1w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dev: true /@eslint/object-schema@2.1.4: resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dev: true /@floating-ui/core@1.6.3: resolution: {integrity: sha512-1ZpCvYf788/ZXOhRQGFxnYQOVgeU+pi0i+d0Ow34La7qjIXETi6RNswGVKkA6KcDO8/+Ysu2E/CeUmmeEBDvTg==} dependencies: '@floating-ui/utils': 0.2.3 dev: false /@floating-ui/dom@1.6.6: resolution: {integrity: sha512-qiTYajAnh3P+38kECeffMSQgbvXty2VB6rS+42iWR4FPIlZjLK84E9qtLnMTLIpPz2znD/TaFqaiavMUrS+Hcw==} dependencies: '@floating-ui/core': 1.6.3 '@floating-ui/utils': 0.2.3 dev: false /@floating-ui/react-dom@2.1.1(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' dependencies: '@floating-ui/dom': 1.6.6 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false /@floating-ui/utils@0.2.3: resolution: {integrity: sha512-XGndio0l5/Gvd6CLIABvsav9HHezgDFFhDfHk1bvLfr9ni8dojqLSvBbotJEjmIwNHL7vK4QzBJTdBRoB+c1ww==} dev: false /@graphql-typed-document-node/core@3.2.0(graphql@16.8.1): resolution: {integrity: sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==} peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 dependencies: graphql: 16.8.1 dev: false /@humanwhocodes/config-array@0.11.14: resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} deprecated: Use @eslint/config-array instead dependencies: '@humanwhocodes/object-schema': 2.0.3 debug: 4.3.5(supports-color@9.4.0) minimatch: 3.1.2 transitivePeerDependencies: - supports-color dev: true /@humanwhocodes/module-importer@1.0.1: resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} dev: true /@humanwhocodes/object-schema@2.0.3: resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} deprecated: Use @eslint/object-schema instead dev: true /@humanwhocodes/retry@0.3.0: resolution: {integrity: sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==} engines: {node: '>=18.18'} dev: true /@jest/expect-utils@29.7.0: resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: jest-get-type: 29.6.3 /@jest/schemas@29.6.3: resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@sinclair/typebox': 0.27.8 /@jest/types@29.6.3: resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 '@types/node': 20.12.12 '@types/yargs': 17.0.32 chalk: 4.1.2 /@jridgewell/gen-mapping@0.3.5: resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} dependencies: '@jridgewell/set-array': 1.2.1 '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping': 0.3.25 /@jridgewell/resolve-uri@3.1.2: resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} /@jridgewell/set-array@1.2.1: resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} /@jridgewell/source-map@0.3.6: resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} dependencies: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 dev: true /@jridgewell/sourcemap-codec@1.4.15: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} /@jridgewell/trace-mapping@0.3.25: resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} dependencies: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.4.15 /@jsdoc/salty@0.2.8: resolution: {integrity: sha512-5e+SFVavj1ORKlKaKr2BmTOekmXbelU7dC0cDkQLqag7xfuTPuGMUFx7KWJuv4bYZrTsoL2Z18VVCOKYxzoHcg==} engines: {node: '>=v12.0.0'} dependencies: lodash: 4.17.21 dev: true /@mui/base@5.0.0-beta.40(@types/react@18.2.72)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ==} engines: {node: '>=12.0.0'} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 react: ^17.0.0 || ^18.0.0 react-dom: ^17.0.0 || ^18.0.0 peerDependenciesMeta: '@types/react': optional: true dependencies: '@babel/runtime': 7.24.7 '@floating-ui/react-dom': 2.1.1(react-dom@18.2.0)(react@18.2.0) '@mui/types': 7.2.14(@types/react@18.2.72) '@mui/utils': 5.15.20(@types/react@18.2.72)(react@18.2.0) '@popperjs/core': 2.11.8 '@types/react': 18.2.72 clsx: 2.1.1 prop-types: 15.8.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false /@mui/core-downloads-tracker@5.15.20: resolution: {integrity: sha512-DoL2ppgldL16utL8nNyj/P12f8mCNdx/Hb/AJnX9rLY4b52hCMIx1kH83pbXQ6uMy6n54M3StmEbvSGoj2OFuA==} dev: false /@mui/icons-material@5.15.18(@mui/material@5.15.18)(@types/react@18.2.72)(react@18.2.0): resolution: {integrity: sha512-jGhyw02TSLM0NgW+MDQRLLRUD/K4eN9rlK2pTBTL1OtzyZmQ8nB060zK1wA0b7cVrIiG+zyrRmNAvGWXwm2N9Q==} engines: {node: '>=12.0.0'} peerDependencies: '@mui/material': ^5.0.0 '@types/react': ^17.0.0 || ^18.0.0 react: ^17.0.0 || ^18.0.0 peerDependenciesMeta: '@types/react': optional: true dependencies: '@babel/runtime': 7.24.7 '@mui/material': 5.15.18(@emotion/react@11.11.4)(@emotion/styled@11.11.5)(@types/react@18.2.72)(react-dom@18.2.0)(react@18.2.0) '@types/react': 18.2.72 react: 18.2.0 dev: false /@mui/material@5.15.18(@emotion/react@11.11.4)(@emotion/styled@11.11.5)(@types/react@18.2.72)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-n+/dsiqux74fFfcRUJjok+ieNQ7+BEk6/OwX9cLcLvriZrZb+/7Y8+Fd2HlUUbn5N0CDurgAHm0VH1DqyJ9HAw==} engines: {node: '>=12.0.0'} peerDependencies: '@emotion/react': ^11.5.0 '@emotion/styled': ^11.3.0 '@types/react': ^17.0.0 || ^18.0.0 react: ^17.0.0 || ^18.0.0 react-dom: ^17.0.0 || ^18.0.0 peerDependenciesMeta: '@emotion/react': optional: true '@emotion/styled': optional: true '@types/react': optional: true dependencies: '@babel/runtime': 7.24.7 '@emotion/react': 11.11.4(@types/react@18.2.72)(react@18.2.0) '@emotion/styled': 11.11.5(@emotion/react@11.11.4)(@types/react@18.2.72)(react@18.2.0) '@mui/base': 5.0.0-beta.40(@types/react@18.2.72)(react-dom@18.2.0)(react@18.2.0) '@mui/core-downloads-tracker': 5.15.20 '@mui/system': 5.15.20(@emotion/react@11.11.4)(@emotion/styled@11.11.5)(@types/react@18.2.72)(react@18.2.0) '@mui/types': 7.2.14(@types/react@18.2.72) '@mui/utils': 5.15.20(@types/react@18.2.72)(react@18.2.0) '@types/react': 18.2.72 '@types/react-transition-group': 4.4.10 clsx: 2.1.1 csstype: 3.1.3 prop-types: 15.8.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-is: 18.3.1 react-transition-group: 4.4.5(react-dom@18.2.0)(react@18.2.0) dev: false /@mui/private-theming@5.15.20(@types/react@18.2.72)(react@18.2.0): resolution: {integrity: sha512-BK8F94AIqSrnaPYXf2KAOjGZJgWfvqAVQ2gVR3EryvQFtuBnG6RwodxrCvd3B48VuMy6Wsk897+lQMUxJyk+6g==} engines: {node: '>=12.0.0'} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 react: ^17.0.0 || ^18.0.0 peerDependenciesMeta: '@types/react': optional: true dependencies: '@babel/runtime': 7.24.7 '@mui/utils': 5.15.20(@types/react@18.2.72)(react@18.2.0) '@types/react': 18.2.72 prop-types: 15.8.1 react: 18.2.0 dev: false /@mui/styled-engine@5.15.14(@emotion/react@11.11.4)(@emotion/styled@11.11.5)(react@18.2.0): resolution: {integrity: sha512-RILkuVD8gY6PvjZjqnWhz8fu68dVkqhM5+jYWfB5yhlSQKg+2rHkmEwm75XIeAqI3qwOndK6zELK5H6Zxn4NHw==} engines: {node: '>=12.0.0'} peerDependencies: '@emotion/react': ^11.4.1 '@emotion/styled': ^11.3.0 react: ^17.0.0 || ^18.0.0 peerDependenciesMeta: '@emotion/react': optional: true '@emotion/styled': optional: true dependencies: '@babel/runtime': 7.24.7 '@emotion/cache': 11.11.0 '@emotion/react': 11.11.4(@types/react@18.2.72)(react@18.2.0) '@emotion/styled': 11.11.5(@emotion/react@11.11.4)(@types/react@18.2.72)(react@18.2.0) csstype: 3.1.3 prop-types: 15.8.1 react: 18.2.0 dev: false /@mui/system@5.15.20(@emotion/react@11.11.4)(@emotion/styled@11.11.5)(@types/react@18.2.72)(react@18.2.0): resolution: {integrity: sha512-LoMq4IlAAhxzL2VNUDBTQxAb4chnBe8JvRINVNDiMtHE2PiPOoHlhOPutSxEbaL5mkECPVWSv6p8JEV+uykwIA==} engines: {node: '>=12.0.0'} peerDependencies: '@emotion/react': ^11.5.0 '@emotion/styled': ^11.3.0 '@types/react': ^17.0.0 || ^18.0.0 react: ^17.0.0 || ^18.0.0 peerDependenciesMeta: '@emotion/react': optional: true '@emotion/styled': optional: true '@types/react': optional: true dependencies: '@babel/runtime': 7.24.7 '@emotion/react': 11.11.4(@types/react@18.2.72)(react@18.2.0) '@emotion/styled': 11.11.5(@emotion/react@11.11.4)(@types/react@18.2.72)(react@18.2.0) '@mui/private-theming': 5.15.20(@types/react@18.2.72)(react@18.2.0) '@mui/styled-engine': 5.15.14(@emotion/react@11.11.4)(@emotion/styled@11.11.5)(react@18.2.0) '@mui/types': 7.2.14(@types/react@18.2.72) '@mui/utils': 5.15.20(@types/react@18.2.72)(react@18.2.0) '@types/react': 18.2.72 clsx: 2.1.1 csstype: 3.1.3 prop-types: 15.8.1 react: 18.2.0 dev: false /@mui/types@7.2.14(@types/react@18.2.72): resolution: {integrity: sha512-MZsBZ4q4HfzBsywtXgM1Ksj6HDThtiwmOKUXH1pKYISI9gAVXCNHNpo7TlGoGrBaYWZTdNoirIN7JsQcQUjmQQ==} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 peerDependenciesMeta: '@types/react': optional: true dependencies: '@types/react': 18.2.72 dev: false /@mui/utils@5.15.20(@types/react@18.2.72)(react@18.2.0): resolution: {integrity: sha512-mAbYx0sovrnpAu1zHc3MDIhPqL8RPVC5W5xcO1b7PiSCJPtckIZmBkp8hefamAvUiAV8gpfMOM6Zb+eSisbI2A==} engines: {node: '>=12.0.0'} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 react: ^17.0.0 || ^18.0.0 peerDependenciesMeta: '@types/react': optional: true dependencies: '@babel/runtime': 7.24.7 '@types/prop-types': 15.7.12 '@types/react': 18.2.72 prop-types: 15.8.1 react: 18.2.0 react-is: 18.3.1 dev: false /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} dependencies: '@nodelib/fs.stat': 2.0.5 run-parallel: 1.2.0 dev: true /@nodelib/fs.stat@2.0.5: resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} engines: {node: '>= 8'} dev: true /@nodelib/fs.walk@1.2.8: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} dependencies: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 dev: true /@novnc/novnc@1.4.0: resolution: {integrity: sha512-kW6ALMc5BuH08e/ond/I1naYcfjc19JYMN1EdtmgjjjzPGCjW8fMtVM3MwM6q7YLRjPlQ3orEvoKMgSS7RkEVQ==} dev: false /@pkgr/core@0.1.1: resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} dev: true /@popperjs/core@2.11.8: resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} dev: false /@remix-run/router@1.15.3: resolution: {integrity: sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w==} engines: {node: '>=14.0.0'} dev: false /@sinclair/typebox@0.27.8: resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} /@sinonjs/commons@2.0.0: resolution: {integrity: sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==} dependencies: type-detect: 4.0.8 dev: true /@sinonjs/commons@3.0.1: resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} dependencies: type-detect: 4.0.8 dev: true /@sinonjs/fake-timers@11.2.2: resolution: {integrity: sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==} dependencies: '@sinonjs/commons': 3.0.1 dev: true /@sinonjs/samsam@8.0.0: resolution: {integrity: sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==} dependencies: '@sinonjs/commons': 2.0.0 lodash.get: 4.4.2 type-detect: 4.0.8 dev: true /@sinonjs/text-encoding@0.7.2: resolution: {integrity: sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==} dev: true /@testing-library/dom@10.2.0: resolution: {integrity: sha512-CytIvb6tVOADRngTHGWNxH8LPgO/3hi/BdCEHOf7Qd2GvZVClhVP0Wo/QHzWhpki49Bk0b4VT6xpt3fx8HTSIw==} engines: {node: '>=18'} dependencies: '@babel/code-frame': 7.24.7 '@babel/runtime': 7.24.7 '@types/aria-query': 5.0.4 aria-query: 5.3.0 chalk: 4.1.2 dom-accessibility-api: 0.5.16 lz-string: 1.5.0 pretty-format: 27.5.1 dev: true /@testing-library/dom@9.3.4: resolution: {integrity: sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==} engines: {node: '>=14'} dependencies: '@babel/code-frame': 7.24.7 '@babel/runtime': 7.24.7 '@types/aria-query': 5.0.4 aria-query: 5.1.3 chalk: 4.1.2 dom-accessibility-api: 0.5.16 lz-string: 1.5.0 pretty-format: 27.5.1 dev: true /@testing-library/jest-dom@6.4.5(@types/jest@29.5.12): resolution: {integrity: sha512-AguB9yvTXmCnySBP1lWjfNNUwpbElsaQ567lt2VdGqAdHtpieLgjmcVyv1q7PMIvLbgpDdkWV5Ydv3FEejyp2A==} engines: {node: '>=14', npm: '>=6', yarn: '>=1'} peerDependencies: '@jest/globals': '>= 28' '@types/bun': latest '@types/jest': '>= 28' jest: '>= 28' vitest: '>= 0.32' peerDependenciesMeta: '@jest/globals': optional: true '@types/bun': optional: true '@types/jest': optional: true jest: optional: true vitest: optional: true dependencies: '@adobe/css-tools': 4.4.0 '@babel/runtime': 7.24.7 '@types/jest': 29.5.12 aria-query: 5.3.0 chalk: 3.0.0 css.escape: 1.5.1 dom-accessibility-api: 0.6.3 lodash: 4.17.21 redent: 3.0.0 dev: true /@testing-library/react@14.3.1(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-H99XjUhWQw0lTgyMN05W3xQG1Nh4lq574D8keFf1dDoNTJgp66VbJozRaczoF+wsiaPJNt/TcnfpLGufGxSrZQ==} engines: {node: '>=14'} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 dependencies: '@babel/runtime': 7.24.7 '@testing-library/dom': 9.3.4 '@types/react-dom': 18.2.22 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true /@testing-library/user-event@14.5.2(@testing-library/dom@10.2.0): resolution: {integrity: sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==} engines: {node: '>=12', npm: '>=6'} peerDependencies: '@testing-library/dom': '>=7.21.4' dependencies: '@testing-library/dom': 10.2.0 dev: true /@types/aria-query@5.0.4: resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} dev: true /@types/history@4.7.11: resolution: {integrity: sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==} dev: false /@types/istanbul-lib-coverage@2.0.6: resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} /@types/istanbul-lib-report@3.0.3: resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} dependencies: '@types/istanbul-lib-coverage': 2.0.6 /@types/istanbul-reports@3.0.4: resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} dependencies: '@types/istanbul-lib-report': 3.0.3 /@types/jest@29.5.12: resolution: {integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==} dependencies: expect: 29.7.0 pretty-format: 29.7.0 /@types/json-schema@7.0.15: resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} dev: true /@types/json5@0.0.29: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true /@types/linkify-it@5.0.0: resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} dev: true /@types/markdown-it@14.1.1: resolution: {integrity: sha512-4NpsnpYl2Gt1ljyBGrKMxFYAYvpqbnnkgP/i/g+NLpjEUa3obn1XJCur9YbEXKDAkaXqsR1LbDnGEJ0MmKFxfg==} dependencies: '@types/linkify-it': 5.0.0 '@types/mdurl': 2.0.0 dev: true /@types/mdurl@2.0.0: resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} dev: true /@types/node@20.12.12: resolution: {integrity: sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==} dependencies: undici-types: 5.26.5 /@types/parse-json@4.0.2: resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} dev: false /@types/prop-types@15.7.12: resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} /@types/react-dom@18.2.22: resolution: {integrity: sha512-fHkBXPeNtfvri6gdsMYyW+dW7RXFo6Ad09nLFK0VQWR7yGLai/Cyvyj696gbwYvBnhGtevUG9cET0pmUbMtoPQ==} dependencies: '@types/react': 18.2.72 /@types/react-modal@3.16.3: resolution: {integrity: sha512-xXuGavyEGaFQDgBv4UVm8/ZsG+qxeQ7f77yNrW3n+1J6XAstUy5rYHeIHPh1KzsGc6IkCIdu6lQ2xWzu1jBTLg==} dependencies: '@types/react': 18.2.72 dev: false /@types/react-router-dom@5.3.3: resolution: {integrity: sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==} dependencies: '@types/history': 4.7.11 '@types/react': 18.2.72 '@types/react-router': 5.1.20 dev: false /@types/react-router@5.1.20: resolution: {integrity: sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==} dependencies: '@types/history': 4.7.11 '@types/react': 18.2.72 dev: false /@types/react-transition-group@4.4.10: resolution: {integrity: sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==} dependencies: '@types/react': 18.2.72 dev: false /@types/react@18.2.72: resolution: {integrity: sha512-/e7GWxGzXQF7OJAua7UAYqYi/4VpXEfbGtmYQcAQwP3SjjjAXfybTf/JK5S+SaetB/ChXl8Y2g1hCsj7jDXxcg==} dependencies: '@types/prop-types': 15.7.12 csstype: 3.1.3 /@types/semver@7.5.8: resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} dev: true /@types/stack-utils@2.0.3: resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} /@types/yargs-parser@21.0.3: resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} /@types/yargs@17.0.32: resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==} dependencies: '@types/yargs-parser': 21.0.3 /@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.0)(typescript@5.4.5): resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: '@typescript-eslint/parser': ^5.0.0 eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: '@eslint-community/regexpp': 4.10.1 '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.4.5) debug: 4.3.5(supports-color@9.4.0) eslint: 8.57.0 graphemer: 1.4.0 ignore: 5.3.1 natural-compare-lite: 1.4.0 semver: 7.6.2 tsutils: 3.21.0(typescript@5.4.5) typescript: 5.4.5 transitivePeerDependencies: - supports-color dev: true /@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.5): resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.5) debug: 4.3.5(supports-color@9.4.0) eslint: 8.57.0 typescript: 5.4.5 transitivePeerDependencies: - supports-color dev: true /@typescript-eslint/scope-manager@5.62.0: resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 dev: true /@typescript-eslint/type-utils@5.62.0(eslint@8.57.0)(typescript@5.4.5): resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: '*' typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.5) '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.4.5) debug: 4.3.5(supports-color@9.4.0) eslint: 8.57.0 tsutils: 3.21.0(typescript@5.4.5) typescript: 5.4.5 transitivePeerDependencies: - supports-color dev: true /@typescript-eslint/types@5.62.0: resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true /@typescript-eslint/typescript-estree@5.62.0(typescript@5.4.5): resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 debug: 4.3.5(supports-color@9.4.0) globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.2 tsutils: 3.21.0(typescript@5.4.5) typescript: 5.4.5 transitivePeerDependencies: - supports-color dev: true /@typescript-eslint/utils@5.62.0(eslint@8.57.0)(typescript@5.4.5): resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@types/json-schema': 7.0.15 '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.5) eslint: 8.57.0 eslint-scope: 5.1.1 semver: 7.6.2 transitivePeerDependencies: - supports-color - typescript dev: true /@typescript-eslint/visitor-keys@5.62.0: resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: '@typescript-eslint/types': 5.62.0 eslint-visitor-keys: 3.4.3 dev: true /@ungap/structured-clone@1.2.0: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} dev: true /@wry/caches@1.0.1: resolution: {integrity: sha512-bXuaUNLVVkD20wcGBWRyo7j9N3TxePEWFZj2Y+r9OoUzfqmavM84+mFykRicNsBqatba5JLay1t48wxaXaWnlA==} engines: {node: '>=8'} dependencies: tslib: 2.6.3 dev: false /@wry/context@0.7.4: resolution: {integrity: sha512-jmT7Sb4ZQWI5iyu3lobQxICu2nC/vbUhP0vIdd6tHC9PTfenmRmuIFqktc6GH9cgi+ZHnsLWPvfSvc4DrYmKiQ==} engines: {node: '>=8'} dependencies: tslib: 2.6.3 dev: false /@wry/equality@0.5.7: resolution: {integrity: sha512-BRFORjsTuQv5gxcXsuDXx6oGRhuVsEGwZy6LOzRRfgu+eSfxbhUQ9L9YtSEIuIjY/o7g3iWFjrc5eSY1GXP2Dw==} engines: {node: '>=8'} dependencies: tslib: 2.6.3 dev: false /@wry/trie@0.4.3: resolution: {integrity: sha512-I6bHwH0fSf6RqQcnnXLJKhkSXG45MFral3GxPaY4uAl0LYDZM+YDVDAiU9bYwjTuysy1S0IeecWtmq1SZA3M1w==} engines: {node: '>=8'} dependencies: tslib: 2.6.3 dev: false /@wry/trie@0.5.0: resolution: {integrity: sha512-FNoYzHawTMk/6KMQoEG5O4PuioX19UbwdQKF44yw0nLfOypfQdjtfZzo/UIJWAJ23sNIFbD1Ug9lbaDGMwbqQA==} engines: {node: '>=8'} dependencies: tslib: 2.6.3 dev: false /accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} dependencies: mime-types: 2.1.35 negotiator: 0.6.3 dev: true /acorn-jsx@5.3.2(acorn@8.12.0): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: acorn: 8.12.0 dev: true /acorn@8.12.0: resolution: {integrity: sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==} engines: {node: '>=0.4.0'} hasBin: true dev: true /ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 json-schema-traverse: 0.4.1 uri-js: 4.4.1 dev: true /ansi-colors@4.1.1: resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} engines: {node: '>=6'} dev: true /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} dependencies: color-convert: 1.9.3 /ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} dependencies: color-convert: 2.0.1 /ansi-styles@5.2.0: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} /anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} dependencies: normalize-path: 3.0.0 picomatch: 2.3.1 dev: true /append-field@1.0.0: resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} dev: true /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} dev: true /aria-query@5.1.3: resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} dependencies: deep-equal: 2.2.3 dev: true /aria-query@5.3.0: resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} dependencies: dequal: 2.0.3 dev: true /array-buffer-byte-length@1.0.1: resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 is-array-buffer: 3.0.4 dev: true /array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} dev: true /array-includes@3.1.8: resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-object-atoms: 1.0.0 get-intrinsic: 1.2.4 is-string: 1.0.7 dev: true /array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} dev: true /array.prototype.findlast@1.2.5: resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-errors: 1.3.0 es-object-atoms: 1.0.0 es-shim-unscopables: 1.0.2 dev: true /array.prototype.findlastindex@1.2.5: resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-errors: 1.3.0 es-object-atoms: 1.0.0 es-shim-unscopables: 1.0.2 dev: true /array.prototype.flat@1.3.2: resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-shim-unscopables: 1.0.2 dev: true /array.prototype.flatmap@1.3.2: resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-shim-unscopables: 1.0.2 dev: true /array.prototype.toreversed@1.1.2: resolution: {integrity: sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-shim-unscopables: 1.0.2 dev: true /array.prototype.tosorted@1.1.4: resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-errors: 1.3.0 es-shim-unscopables: 1.0.2 dev: true /arraybuffer.prototype.slice@1.0.3: resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} engines: {node: '>= 0.4'} dependencies: array-buffer-byte-length: 1.0.1 call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-errors: 1.3.0 get-intrinsic: 1.2.4 is-array-buffer: 3.0.4 is-shared-array-buffer: 1.0.3 dev: true /async@3.2.5: resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} dev: false /available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} dependencies: possible-typed-array-names: 1.0.0 dev: true /babel-literal-to-ast@2.1.0(@babel/core@7.24.7): resolution: {integrity: sha512-CxfpQ0ysQ0bZOhlaPgcWjl79Em16Rhqc6++UAFn0A3duiXmuyhhj8yyl9PYbj0I0CyjrHovdDbp2QEKT7uIMxw==} peerDependencies: '@babel/core': ^7.1.2 dependencies: '@babel/core': 7.24.7 '@babel/parser': 7.24.7 '@babel/traverse': 7.24.7 '@babel/types': 7.24.7 transitivePeerDependencies: - supports-color dev: false /babel-plugin-macros@2.8.0: resolution: {integrity: sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==} dependencies: '@babel/runtime': 7.24.7 cosmiconfig: 6.0.0 resolve: 1.22.8 dev: false /babel-plugin-macros@3.1.0: resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} engines: {node: '>=10', npm: '>=6'} dependencies: '@babel/runtime': 7.24.7 cosmiconfig: 7.1.0 resolve: 1.22.8 dev: false /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} /batch@0.6.1: resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==} dev: true /binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} dev: true /bluebird@3.7.2: resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} dev: true /body-parser@1.20.2(supports-color@9.4.0): resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} dependencies: bytes: 3.1.2 content-type: 1.0.5 debug: 2.6.9(supports-color@9.4.0) depd: 2.0.0 destroy: 1.2.0 http-errors: 2.0.0 iconv-lite: 0.4.24 on-finished: 2.4.1 qs: 6.11.0 raw-body: 2.5.2 type-is: 1.6.18 unpipe: 1.0.0 transitivePeerDependencies: - supports-color dev: true /brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 /brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} dependencies: balanced-match: 1.0.2 /braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} dependencies: fill-range: 7.1.1 /browser-stdout@1.3.1: resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} dev: true /browserslist@4.23.1: resolution: {integrity: sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: caniuse-lite: 1.0.30001637 electron-to-chromium: 1.4.812 node-releases: 2.0.14 update-browserslist-db: 1.0.16(browserslist@4.23.1) /btoa@1.2.1: resolution: {integrity: sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==} engines: {node: '>= 0.4.0'} hasBin: true dev: false /buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} dev: true /builtins@5.1.0: resolution: {integrity: sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==} dependencies: semver: 7.6.2 dev: true /busboy@1.6.0: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} dependencies: streamsearch: 1.1.0 dev: true /bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} dev: true /call-bind@1.0.7: resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} engines: {node: '>= 0.4'} dependencies: es-define-property: 1.0.0 es-errors: 1.3.0 function-bind: 1.1.2 get-intrinsic: 1.2.4 set-function-length: 1.2.2 dev: true /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} /camel-case@4.1.2: resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} dependencies: pascal-case: 3.1.2 tslib: 2.6.3 dev: true /camelcase@6.3.0: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} dev: true /caniuse-lite@1.0.30001637: resolution: {integrity: sha512-1x0qRI1mD1o9e+7mBI7XtzFAP4XszbHaVWsMiGbSPLYekKTJF7K+FNk6AsXH4sUpc+qrsI3pVgf1Jdl/uGkuSQ==} /catharsis@0.9.0: resolution: {integrity: sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==} engines: {node: '>= 10'} dependencies: lodash: 4.17.21 dev: true /chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} dependencies: ansi-styles: 3.2.1 escape-string-regexp: 1.0.5 supports-color: 5.5.0 /chalk@3.0.0: resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==} engines: {node: '>=8'} dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 dev: true /chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 /charenc@0.0.2: resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} dev: true /chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} dependencies: anymatch: 3.1.3 braces: 3.0.3 glob-parent: 5.1.2 is-binary-path: 2.1.0 is-glob: 4.0.3 normalize-path: 3.0.0 readdirp: 3.6.0 optionalDependencies: fsevents: 2.3.3 dev: true /ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} /clean-css@5.3.3: resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==} engines: {node: '>= 10.0'} dependencies: source-map: 0.6.1 dev: true /clean-jsdoc-theme@4.3.0(jsdoc@4.0.3): resolution: {integrity: sha512-QMrBdZ2KdPt6V2Ytg7dIt0/q32U4COpxvR0UDhPjRRKRL0o0MvRCR5YpY37/4rPF1SI1AYEKAWyof7ndCb/dzA==} peerDependencies: jsdoc: '>=3.x <=4.x' dependencies: '@jsdoc/salty': 0.2.8 fs-extra: 10.1.0 html-minifier-terser: 7.2.0 jsdoc: 4.0.3 klaw-sync: 6.0.0 lodash: 4.17.21 showdown: 2.1.0 dev: true /cliui@7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} dependencies: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 /clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} dev: false /color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: color-name: 1.1.3 /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} dependencies: color-name: 1.1.4 /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} /commander@10.0.1: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} dev: true /commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} dev: true /commander@9.5.0: resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} engines: {node: ^12.20.0 || >=14} dev: true /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} /concat-stream@1.6.2: resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} engines: {'0': node >= 0.8} dependencies: buffer-from: 1.1.2 inherits: 2.0.4 readable-stream: 2.3.8 typedarray: 0.0.6 dev: true /content-disposition@0.5.4: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} dependencies: safe-buffer: 5.2.1 dev: true /content-type@1.0.5: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} dev: true /convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} dev: false /convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} /cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} dev: true /cookie@0.6.0: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} dev: true /core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} /cosmiconfig@6.0.0: resolution: {integrity: sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==} engines: {node: '>=8'} dependencies: '@types/parse-json': 4.0.2 import-fresh: 3.3.0 parse-json: 5.2.0 path-type: 4.0.0 yaml: 1.10.2 dev: false /cosmiconfig@7.1.0: resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} engines: {node: '>=10'} dependencies: '@types/parse-json': 4.0.2 import-fresh: 3.3.0 parse-json: 5.2.0 path-type: 4.0.0 yaml: 1.10.2 dev: false /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 dev: true /crypt@0.0.2: resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} dev: true /css.escape@1.5.1: resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} dev: true /csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} /data-view-buffer@1.0.1: resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 es-errors: 1.3.0 is-data-view: 1.0.1 dev: true /data-view-byte-length@1.0.1: resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 es-errors: 1.3.0 is-data-view: 1.0.1 dev: true /data-view-byte-offset@1.0.0: resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 es-errors: 1.3.0 is-data-view: 1.0.1 dev: true /debug@2.6.9(supports-color@9.4.0): resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: supports-color: '*' peerDependenciesMeta: supports-color: optional: true dependencies: ms: 2.0.0 supports-color: 9.4.0 dev: true /debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: supports-color: '*' peerDependenciesMeta: supports-color: optional: true dependencies: ms: 2.1.3 dev: true /debug@4.3.4(supports-color@8.1.1): resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' peerDependenciesMeta: supports-color: optional: true dependencies: ms: 2.1.2 supports-color: 8.1.1 dev: true /debug@4.3.5(supports-color@9.4.0): resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' peerDependenciesMeta: supports-color: optional: true dependencies: ms: 2.1.2 supports-color: 9.4.0 /decamelize@4.0.0: resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} engines: {node: '>=10'} dev: true /deep-equal@2.2.3: resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==} engines: {node: '>= 0.4'} dependencies: array-buffer-byte-length: 1.0.1 call-bind: 1.0.7 es-get-iterator: 1.1.3 get-intrinsic: 1.2.4 is-arguments: 1.1.1 is-array-buffer: 3.0.4 is-date-object: 1.0.5 is-regex: 1.1.4 is-shared-array-buffer: 1.0.3 isarray: 2.0.5 object-is: 1.1.6 object-keys: 1.1.1 object.assign: 4.1.5 regexp.prototype.flags: 1.5.2 side-channel: 1.0.6 which-boxed-primitive: 1.0.2 which-collection: 1.0.2 which-typed-array: 1.1.15 dev: true /deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true /define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} dependencies: es-define-property: 1.0.0 es-errors: 1.3.0 gopd: 1.0.1 dev: true /define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} dependencies: define-data-property: 1.1.4 has-property-descriptors: 1.0.2 object-keys: 1.1.1 dev: true /depd@1.1.2: resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} engines: {node: '>= 0.6'} dev: true /depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} dev: true /dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} dev: true /destroy@1.2.0: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} dev: true /diff-sequences@29.6.3: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} /diff@5.0.0: resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} engines: {node: '>=0.3.1'} dev: true /diff@5.2.0: resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} engines: {node: '>=0.3.1'} dev: true /dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} dependencies: path-type: 4.0.0 dev: true /doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} dependencies: esutils: 2.0.3 dev: true /doctrine@3.0.0: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} dependencies: esutils: 2.0.3 dev: true /dom-accessibility-api@0.5.16: resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} dev: true /dom-accessibility-api@0.6.3: resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} dev: true /dom-helpers@5.2.1: resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} dependencies: '@babel/runtime': 7.24.7 csstype: 3.1.3 dev: false /dot-case@3.0.4: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} dependencies: no-case: 3.0.4 tslib: 2.6.3 dev: true /duplexer@0.1.2: resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} dev: false /ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} dev: true /ejs@3.1.10: resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} engines: {node: '>=0.10.0'} hasBin: true dependencies: jake: 10.9.1 dev: false /electron-to-chromium@1.4.812: resolution: {integrity: sha512-7L8fC2Ey/b6SePDFKR2zHAy4mbdp1/38Yk5TsARO66W3hC5KEaeKMMHoxwtuH+jcu2AYLSn9QX04i95t6Fl1Hg==} /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} /encodeurl@1.0.2: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} dev: true /enhanced-resolve@5.17.0: resolution: {integrity: sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==} engines: {node: '>=10.13.0'} dependencies: graceful-fs: 4.2.11 tapable: 2.2.1 dev: true /entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} dev: true /error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: is-arrayish: 0.2.1 /es-abstract@1.23.3: resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} engines: {node: '>= 0.4'} dependencies: array-buffer-byte-length: 1.0.1 arraybuffer.prototype.slice: 1.0.3 available-typed-arrays: 1.0.7 call-bind: 1.0.7 data-view-buffer: 1.0.1 data-view-byte-length: 1.0.1 data-view-byte-offset: 1.0.0 es-define-property: 1.0.0 es-errors: 1.3.0 es-object-atoms: 1.0.0 es-set-tostringtag: 2.0.3 es-to-primitive: 1.2.1 function.prototype.name: 1.1.6 get-intrinsic: 1.2.4 get-symbol-description: 1.0.2 globalthis: 1.0.4 gopd: 1.0.1 has-property-descriptors: 1.0.2 has-proto: 1.0.3 has-symbols: 1.0.3 hasown: 2.0.2 internal-slot: 1.0.7 is-array-buffer: 3.0.4 is-callable: 1.2.7 is-data-view: 1.0.1 is-negative-zero: 2.0.3 is-regex: 1.1.4 is-shared-array-buffer: 1.0.3 is-string: 1.0.7 is-typed-array: 1.1.13 is-weakref: 1.0.2 object-inspect: 1.13.2 object-keys: 1.1.1 object.assign: 4.1.5 regexp.prototype.flags: 1.5.2 safe-array-concat: 1.1.2 safe-regex-test: 1.0.3 string.prototype.trim: 1.2.9 string.prototype.trimend: 1.0.8 string.prototype.trimstart: 1.0.8 typed-array-buffer: 1.0.2 typed-array-byte-length: 1.0.1 typed-array-byte-offset: 1.0.2 typed-array-length: 1.0.6 unbox-primitive: 1.0.2 which-typed-array: 1.1.15 dev: true /es-define-property@1.0.0: resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} engines: {node: '>= 0.4'} dependencies: get-intrinsic: 1.2.4 dev: true /es-errors@1.3.0: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} dev: true /es-get-iterator@1.1.3: resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} dependencies: call-bind: 1.0.7 get-intrinsic: 1.2.4 has-symbols: 1.0.3 is-arguments: 1.1.1 is-map: 2.0.3 is-set: 2.0.3 is-string: 1.0.7 isarray: 2.0.5 stop-iteration-iterator: 1.0.0 dev: true /es-iterator-helpers@1.0.19: resolution: {integrity: sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-errors: 1.3.0 es-set-tostringtag: 2.0.3 function-bind: 1.1.2 get-intrinsic: 1.2.4 globalthis: 1.0.4 has-property-descriptors: 1.0.2 has-proto: 1.0.3 has-symbols: 1.0.3 internal-slot: 1.0.7 iterator.prototype: 1.1.2 safe-array-concat: 1.1.2 dev: true /es-object-atoms@1.0.0: resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} engines: {node: '>= 0.4'} dependencies: es-errors: 1.3.0 dev: true /es-set-tostringtag@2.0.3: resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} engines: {node: '>= 0.4'} dependencies: get-intrinsic: 1.2.4 has-tostringtag: 1.0.2 hasown: 2.0.2 dev: true /es-shim-unscopables@1.0.2: resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} dependencies: hasown: 2.0.2 dev: true /es-to-primitive@1.2.1: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} engines: {node: '>= 0.4'} dependencies: is-callable: 1.2.7 is-date-object: 1.0.5 is-symbol: 1.0.4 dev: true /esbuild@0.19.12: resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} engines: {node: '>=12'} hasBin: true requiresBuild: true optionalDependencies: '@esbuild/aix-ppc64': 0.19.12 '@esbuild/android-arm': 0.19.12 '@esbuild/android-arm64': 0.19.12 '@esbuild/android-x64': 0.19.12 '@esbuild/darwin-arm64': 0.19.12 '@esbuild/darwin-x64': 0.19.12 '@esbuild/freebsd-arm64': 0.19.12 '@esbuild/freebsd-x64': 0.19.12 '@esbuild/linux-arm': 0.19.12 '@esbuild/linux-arm64': 0.19.12 '@esbuild/linux-ia32': 0.19.12 '@esbuild/linux-loong64': 0.19.12 '@esbuild/linux-mips64el': 0.19.12 '@esbuild/linux-ppc64': 0.19.12 '@esbuild/linux-riscv64': 0.19.12 '@esbuild/linux-s390x': 0.19.12 '@esbuild/linux-x64': 0.19.12 '@esbuild/netbsd-x64': 0.19.12 '@esbuild/openbsd-x64': 0.19.12 '@esbuild/sunos-x64': 0.19.12 '@esbuild/win32-arm64': 0.19.12 '@esbuild/win32-ia32': 0.19.12 '@esbuild/win32-x64': 0.19.12 dev: true /escalade@3.1.2: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} engines: {node: '>=6'} /escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} /escape-string-regexp@2.0.0: resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} engines: {node: '>=8'} /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} /eslint-compat-utils@0.5.1(eslint@9.5.0): resolution: {integrity: sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==} engines: {node: '>=12'} peerDependencies: eslint: '>=6.0.0' dependencies: eslint: 9.5.0(supports-color@9.4.0) semver: 7.6.2 dev: true /eslint-config-prettier@9.1.0(eslint@9.5.0): resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: eslint: 9.5.0(supports-color@9.4.0) dev: true /eslint-config-standard-jsx@11.0.0(eslint-plugin-react@7.34.3)(eslint@8.57.0): resolution: {integrity: sha512-+1EV/R0JxEK1L0NGolAr8Iktm3Rgotx3BKwgaX+eAuSX8D952LULKtjgZD3F+e6SvibONnhLwoTi9DPxN5LvvQ==} peerDependencies: eslint: ^8.8.0 eslint-plugin-react: ^7.28.0 dependencies: eslint: 8.57.0 eslint-plugin-react: 7.34.3(eslint@8.57.0) dev: true /eslint-config-standard-with-typescript@23.0.0(@typescript-eslint/eslint-plugin@5.62.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.2.0)(eslint@8.57.0)(typescript@5.4.5): resolution: {integrity: sha512-iaaWifImn37Z1OXbNW1es7KI+S7D408F9ys0bpaQf2temeBWlvb0Nc5qHkOgYaRb5QxTZT32GGeN1gtswASOXA==} deprecated: Please use eslint-config-love, instead. peerDependencies: '@typescript-eslint/eslint-plugin': ^5.0.0 eslint: ^8.0.1 eslint-plugin-import: ^2.25.2 eslint-plugin-n: ^15.0.0 eslint-plugin-promise: ^6.0.0 typescript: '*' dependencies: '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.5) eslint: 8.57.0 eslint-config-standard: 17.0.0(eslint-plugin-import@2.29.1)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.2.0)(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.62.0)(eslint@8.57.0) eslint-plugin-n: 15.7.0(eslint@8.57.0) eslint-plugin-promise: 6.2.0(eslint@8.57.0) typescript: 5.4.5 transitivePeerDependencies: - supports-color dev: true /eslint-config-standard@17.0.0(eslint-plugin-import@2.29.1)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.2.0)(eslint@8.57.0): resolution: {integrity: sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg==} peerDependencies: eslint: ^8.0.1 eslint-plugin-import: ^2.25.2 eslint-plugin-n: ^15.0.0 eslint-plugin-promise: ^6.0.0 dependencies: eslint: 8.57.0 eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.62.0)(eslint@8.57.0) eslint-plugin-n: 15.7.0(eslint@8.57.0) eslint-plugin-promise: 6.2.0(eslint@8.57.0) dev: true /eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} dependencies: debug: 3.2.7 is-core-module: 2.14.0 resolve: 1.22.8 transitivePeerDependencies: - supports-color dev: true /eslint-module-utils@2.8.1(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' eslint: '*' eslint-import-resolver-node: '*' eslint-import-resolver-typescript: '*' eslint-import-resolver-webpack: '*' peerDependenciesMeta: '@typescript-eslint/parser': optional: true eslint: optional: true eslint-import-resolver-node: optional: true eslint-import-resolver-typescript: optional: true eslint-import-resolver-webpack: optional: true dependencies: '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.5) debug: 3.2.7 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color dev: true /eslint-plugin-es-x@7.7.0(eslint@9.5.0): resolution: {integrity: sha512-aP3qj8BwiEDPttxQkZdI221DLKq9sI/qHolE2YSQL1/9+xk7dTV+tB1Fz8/IaCA+lnLA1bDEnvaS2LKs0k2Uig==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: eslint: '>=8' dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@9.5.0) '@eslint-community/regexpp': 4.10.1 eslint: 9.5.0(supports-color@9.4.0) eslint-compat-utils: 0.5.1(eslint@9.5.0) dev: true /eslint-plugin-es@4.1.0(eslint@8.57.0): resolution: {integrity: sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==} engines: {node: '>=8.10.0'} peerDependencies: eslint: '>=4.19.1' dependencies: eslint: 8.57.0 eslint-utils: 2.1.0 regexpp: 3.2.0 dev: true /eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0)(eslint@8.57.0): resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 peerDependenciesMeta: '@typescript-eslint/parser': optional: true dependencies: '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.5) array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 array.prototype.flat: 1.3.2 array.prototype.flatmap: 1.3.2 debug: 3.2.7 doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.14.0 is-glob: 4.0.3 minimatch: 3.1.2 object.fromentries: 2.0.8 object.groupby: 1.0.3 object.values: 1.2.0 semver: 6.3.1 tsconfig-paths: 3.15.0 transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color dev: true /eslint-plugin-mocha@10.4.3(eslint@9.5.0): resolution: {integrity: sha512-emc4TVjq5Ht0/upR+psftuz6IBG5q279p+1dSRDeHf+NS9aaerBi3lXKo1SEzwC29hFIW21gO89CEWSvRsi8IQ==} engines: {node: '>=14.0.0'} peerDependencies: eslint: '>=7.0.0' dependencies: eslint: 9.5.0(supports-color@9.4.0) eslint-utils: 3.0.0(eslint@9.5.0) globals: 13.24.0 rambda: 7.5.0 dev: true /eslint-plugin-n@15.7.0(eslint@8.57.0): resolution: {integrity: sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q==} engines: {node: '>=12.22.0'} peerDependencies: eslint: '>=7.0.0' dependencies: builtins: 5.1.0 eslint: 8.57.0 eslint-plugin-es: 4.1.0(eslint@8.57.0) eslint-utils: 3.0.0(eslint@8.57.0) ignore: 5.3.1 is-core-module: 2.14.0 minimatch: 3.1.2 resolve: 1.22.8 semver: 7.6.2 dev: true /eslint-plugin-n@17.9.0(eslint@9.5.0): resolution: {integrity: sha512-CPSaXDXdrT4nsrOrO4mT4VB6FMUkoySRkHWuuJJHVqsIEjIeZgMY1H7AzSwPbDScikBmLN82KeM1u7ixV7PzGg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: '>=8.23.0' dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@9.5.0) enhanced-resolve: 5.17.0 eslint: 9.5.0(supports-color@9.4.0) eslint-plugin-es-x: 7.7.0(eslint@9.5.0) get-tsconfig: 4.7.5 globals: 15.6.0 ignore: 5.3.1 minimatch: 9.0.5 semver: 7.6.2 dev: true /eslint-plugin-no-only-tests@3.1.0: resolution: {integrity: sha512-Lf4YW/bL6Un1R6A76pRZyE1dl1vr31G/ev8UzIc/geCgFWyrKil8hVjYqWVKGB/UIGmb6Slzs9T0wNezdSVegw==} engines: {node: '>=5.0.0'} dev: true /eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0)(eslint@9.5.0)(prettier@3.3.2): resolution: {integrity: sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: '@types/eslint': '>=8.0.0' eslint: '>=8.0.0' eslint-config-prettier: '*' prettier: '>=3.0.0' peerDependenciesMeta: '@types/eslint': optional: true eslint-config-prettier: optional: true dependencies: eslint: 9.5.0(supports-color@9.4.0) eslint-config-prettier: 9.1.0(eslint@9.5.0) prettier: 3.3.2 prettier-linter-helpers: 1.0.0 synckit: 0.8.8 dev: true /eslint-plugin-promise@6.2.0(eslint@8.57.0): resolution: {integrity: sha512-QmAqwizauvnKOlifxyDj2ObfULpHQawlg/zQdgEixur9vl0CvZGv/LCJV2rtj3210QCoeGBzVMfMXqGAOr/4fA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 dependencies: eslint: 8.57.0 dev: true /eslint-plugin-react@7.34.3(eslint@8.57.0): resolution: {integrity: sha512-aoW4MV891jkUulwDApQbPYTVZmeuSyFrudpbTAQuj5Fv8VL+o6df2xIGpw8B0hPjAaih1/Fb0om9grCdyFYemA==} engines: {node: '>=4'} peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 dependencies: array-includes: 3.1.8 array.prototype.findlast: 1.2.5 array.prototype.flatmap: 1.3.2 array.prototype.toreversed: 1.1.2 array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.0.19 eslint: 8.57.0 estraverse: 5.3.0 jsx-ast-utils: 3.3.5 minimatch: 3.1.2 object.entries: 1.1.8 object.fromentries: 2.0.8 object.hasown: 1.1.4 object.values: 1.2.0 prop-types: 15.8.1 resolve: 2.0.0-next.5 semver: 6.3.1 string.prototype.matchall: 4.0.11 dev: true /eslint-scope@5.1.1: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} dependencies: esrecurse: 4.3.0 estraverse: 4.3.0 dev: true /eslint-scope@7.2.2: resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 dev: true /eslint-scope@8.0.1: resolution: {integrity: sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 dev: true /eslint-utils@2.1.0: resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==} engines: {node: '>=6'} dependencies: eslint-visitor-keys: 1.3.0 dev: true /eslint-utils@3.0.0(eslint@8.57.0): resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} peerDependencies: eslint: '>=5' dependencies: eslint: 8.57.0 eslint-visitor-keys: 2.1.0 dev: true /eslint-utils@3.0.0(eslint@9.5.0): resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} peerDependencies: eslint: '>=5' dependencies: eslint: 9.5.0(supports-color@9.4.0) eslint-visitor-keys: 2.1.0 dev: true /eslint-visitor-keys@1.3.0: resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} engines: {node: '>=4'} dev: true /eslint-visitor-keys@2.1.0: resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} engines: {node: '>=10'} dev: true /eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true /eslint-visitor-keys@4.0.0: resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dev: true /eslint@8.57.0: resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@eslint-community/regexpp': 4.10.1 '@eslint/eslintrc': 2.1.4 '@eslint/js': 8.57.0 '@humanwhocodes/config-array': 0.11.14 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 '@ungap/structured-clone': 1.2.0 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 debug: 4.3.5(supports-color@9.4.0) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 esquery: 1.5.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 find-up: 5.0.0 glob-parent: 6.0.2 globals: 13.24.0 graphemer: 1.4.0 ignore: 5.3.1 imurmurhash: 0.1.4 is-glob: 4.0.3 is-path-inside: 3.0.3 js-yaml: 4.1.0 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 lodash.merge: 4.6.2 minimatch: 3.1.2 natural-compare: 1.4.0 optionator: 0.9.4 strip-ansi: 6.0.1 text-table: 0.2.0 transitivePeerDependencies: - supports-color dev: true /eslint@9.5.0(supports-color@9.4.0): resolution: {integrity: sha512-+NAOZFrW/jFTS3dASCGBxX1pkFD0/fsO+hfAkJ4TyYKwgsXZbqzrw+seCYFCcPCYXvnD67tAnglU7GQTz6kcVw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@9.5.0) '@eslint-community/regexpp': 4.10.1 '@eslint/config-array': 0.16.0(supports-color@9.4.0) '@eslint/eslintrc': 3.1.0(supports-color@9.4.0) '@eslint/js': 9.5.0 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.3.0 '@nodelib/fs.walk': 1.2.8 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 debug: 4.3.5(supports-color@9.4.0) escape-string-regexp: 4.0.0 eslint-scope: 8.0.1 eslint-visitor-keys: 4.0.0 espree: 10.1.0 esquery: 1.5.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 8.0.0 find-up: 5.0.0 glob-parent: 6.0.2 ignore: 5.3.1 imurmurhash: 0.1.4 is-glob: 4.0.3 is-path-inside: 3.0.3 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 lodash.merge: 4.6.2 minimatch: 3.1.2 natural-compare: 1.4.0 optionator: 0.9.4 strip-ansi: 6.0.1 text-table: 0.2.0 transitivePeerDependencies: - supports-color dev: true /espree@10.1.0: resolution: {integrity: sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: acorn: 8.12.0 acorn-jsx: 5.3.2(acorn@8.12.0) eslint-visitor-keys: 4.0.0 dev: true /espree@9.6.1: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: acorn: 8.12.0 acorn-jsx: 5.3.2(acorn@8.12.0) eslint-visitor-keys: 3.4.3 dev: true /esquery@1.5.0: resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} engines: {node: '>=0.10'} dependencies: estraverse: 5.3.0 dev: true /esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} dependencies: estraverse: 5.3.0 dev: true /estraverse@4.3.0: resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} engines: {node: '>=4.0'} dev: true /estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} dev: true /esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} dev: true /etag@1.8.1: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} dev: true /exenv@1.2.2: resolution: {integrity: sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==} dev: false /expect@29.7.0: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/expect-utils': 29.7.0 jest-get-type: 29.6.3 jest-matcher-utils: 29.7.0 jest-message-util: 29.7.0 jest-util: 29.7.0 /express@4.19.2(supports-color@9.4.0): resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==} engines: {node: '>= 0.10.0'} dependencies: accepts: 1.3.8 array-flatten: 1.1.1 body-parser: 1.20.2(supports-color@9.4.0) content-disposition: 0.5.4 content-type: 1.0.5 cookie: 0.6.0 cookie-signature: 1.0.6 debug: 2.6.9(supports-color@9.4.0) depd: 2.0.0 encodeurl: 1.0.2 escape-html: 1.0.3 etag: 1.8.1 finalhandler: 1.2.0(supports-color@9.4.0) fresh: 0.5.2 http-errors: 2.0.0 merge-descriptors: 1.0.1 methods: 1.1.2 on-finished: 2.4.1 parseurl: 1.3.3 path-to-regexp: 0.1.7 proxy-addr: 2.0.7 qs: 6.11.0 range-parser: 1.2.1 safe-buffer: 5.2.1 send: 0.18.0(supports-color@9.4.0) serve-static: 1.15.0(supports-color@9.4.0) setprototypeof: 1.2.0 statuses: 2.0.1 type-is: 1.6.18 utils-merge: 1.0.1 vary: 1.1.2 transitivePeerDependencies: - supports-color dev: true /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: true /fast-diff@1.3.0: resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} dev: true /fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 micromatch: 4.0.7 dev: true /fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} dev: true /fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} dev: true /fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} dependencies: reusify: 1.0.4 dev: true /file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} dependencies: flat-cache: 3.2.0 dev: true /file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} dependencies: flat-cache: 4.0.1 dev: true /filelist@1.0.4: resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} dependencies: minimatch: 5.1.6 dev: false /fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} dependencies: to-regex-range: 5.0.1 /finalhandler@1.2.0(supports-color@9.4.0): resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} engines: {node: '>= 0.8'} dependencies: debug: 2.6.9(supports-color@9.4.0) encodeurl: 1.0.2 escape-html: 1.0.3 on-finished: 2.4.1 parseurl: 1.3.3 statuses: 2.0.1 unpipe: 1.0.0 transitivePeerDependencies: - supports-color dev: true /find-root@1.1.0: resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} dev: false /find-up@3.0.0: resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} engines: {node: '>=6'} dependencies: locate-path: 3.0.0 dev: true /find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} dependencies: locate-path: 6.0.0 path-exists: 4.0.0 dev: true /find-up@6.3.0: resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: locate-path: 7.2.0 path-exists: 5.0.0 dev: true /flat-cache@3.2.0: resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} engines: {node: ^10.12.0 || >=12.0.0} dependencies: flatted: 3.3.1 keyv: 4.5.4 rimraf: 3.0.2 dev: true /flat-cache@4.0.1: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} dependencies: flatted: 3.3.1 keyv: 4.5.4 dev: true /flat@5.0.2: resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} hasBin: true dev: true /flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} dev: true /for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} dependencies: is-callable: 1.2.7 dev: true /forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} dev: true /fresh@0.5.2: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} dev: true /fs-extra@10.1.0: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} dependencies: graceful-fs: 4.2.11 jsonfile: 6.1.0 universalify: 2.0.1 dev: true /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} /fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] requiresBuild: true dev: true optional: true /function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} /function.prototype.name@1.1.6: resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 functions-have-names: 1.2.3 dev: true /functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} dev: true /gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} /get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} /get-intrinsic@1.2.4: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} dependencies: es-errors: 1.3.0 function-bind: 1.1.2 has-proto: 1.0.3 has-symbols: 1.0.3 hasown: 2.0.2 dev: true /get-stdin@8.0.0: resolution: {integrity: sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==} engines: {node: '>=10'} dev: true /get-symbol-description@1.0.2: resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 es-errors: 1.3.0 get-intrinsic: 1.2.4 dev: true /get-tsconfig@4.7.5: resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==} dependencies: resolve-pkg-maps: 1.0.0 dev: true /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} dependencies: is-glob: 4.0.3 dev: true /glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} dependencies: is-glob: 4.0.3 dev: true /glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 /glob@8.1.0: resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} engines: {node: '>=12'} deprecated: Glob versions prior to v9 are no longer supported dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 minimatch: 5.0.1 once: 1.4.0 dev: true /globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} /globals@13.24.0: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} dependencies: type-fest: 0.20.2 dev: true /globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} dev: true /globals@15.6.0: resolution: {integrity: sha512-UzcJi88Hw//CurUIRa9Jxb0vgOCcuD/MNjwmXp633cyaRKkCWACkoqHCtfZv43b1kqXGg/fpOa8bwgacCeXsVg==} engines: {node: '>=18'} dev: true /globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} dependencies: define-properties: 1.2.1 gopd: 1.0.1 dev: true /globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} dependencies: array-union: 2.1.0 dir-glob: 3.0.1 fast-glob: 3.3.2 ignore: 5.3.1 merge2: 1.4.1 slash: 3.0.0 dev: true /gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: get-intrinsic: 1.2.4 dev: true /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} /graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} dev: true /graphql-tag@2.12.6(graphql@16.8.1): resolution: {integrity: sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==} engines: {node: '>=10'} peerDependencies: graphql: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 dependencies: graphql: 16.8.1 tslib: 2.6.3 dev: false /graphql.macro@1.4.2(@babel/core@7.24.7)(graphql@16.8.1): resolution: {integrity: sha512-vcIaStPgS65gp5i1M3DSBimNVkyus0Z7k4VObWAyZS319tKlpX/TEIJSWTgOZU5k8dn4RRzGoS/elQhX2E6yBw==} dependencies: '@babel/template': 7.24.7 babel-literal-to-ast: 2.1.0(@babel/core@7.24.7) babel-plugin-macros: 2.8.0 graphql-tag: 2.12.6(graphql@16.8.1) transitivePeerDependencies: - '@babel/core' - graphql - supports-color dev: false /graphql@16.8.1: resolution: {integrity: sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} dev: false /gzip-size@6.0.0: resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==} engines: {node: '>=10'} dependencies: duplexer: 0.1.2 dev: false /has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} dev: true /has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} /has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} dependencies: es-define-property: 1.0.0 dev: true /has-proto@1.0.3: resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} engines: {node: '>= 0.4'} dev: true /has-symbols@1.0.3: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} dev: true /has-tostringtag@1.0.2: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} dependencies: has-symbols: 1.0.3 dev: true /hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} dependencies: function-bind: 1.1.2 /he@1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true dev: true /hoist-non-react-statics@3.3.2: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} dependencies: react-is: 16.13.1 dev: false /html-minifier-terser@7.2.0: resolution: {integrity: sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==} engines: {node: ^14.13.1 || >=16.0.0} hasBin: true dependencies: camel-case: 4.1.2 clean-css: 5.3.3 commander: 10.0.1 entities: 4.5.0 param-case: 3.0.4 relateurl: 0.2.7 terser: 5.31.1 dev: true /http-errors@1.6.3: resolution: {integrity: sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==} engines: {node: '>= 0.6'} dependencies: depd: 1.1.2 inherits: 2.0.3 setprototypeof: 1.1.0 statuses: 1.5.0 dev: true /http-errors@2.0.0: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} dependencies: depd: 2.0.0 inherits: 2.0.4 setprototypeof: 1.2.0 statuses: 2.0.1 toidentifier: 1.0.1 dev: true /iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} dependencies: safer-buffer: 2.1.2 dev: true /ignore@5.3.1: resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} engines: {node: '>= 4'} dev: true /immediate@3.0.6: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} dev: false /import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 /imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} dev: true /indent-string@4.0.0: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} dev: true /inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. dependencies: once: 1.4.0 wrappy: 1.0.2 /inherits@2.0.3: resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} dev: true /inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} /internal-slot@1.0.7: resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} engines: {node: '>= 0.4'} dependencies: es-errors: 1.3.0 hasown: 2.0.2 side-channel: 1.0.6 dev: true /ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} dev: true /is-arguments@1.1.1: resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 has-tostringtag: 1.0.2 dev: true /is-array-buffer@3.0.4: resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 get-intrinsic: 1.2.4 dev: true /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} /is-async-function@2.0.0: resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.2 dev: true /is-bigint@1.0.4: resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} dependencies: has-bigints: 1.0.2 dev: true /is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} dependencies: binary-extensions: 2.3.0 dev: true /is-boolean-object@1.1.2: resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 has-tostringtag: 1.0.2 dev: true /is-buffer@1.1.6: resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} dev: true /is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} dev: true /is-core-module@2.14.0: resolution: {integrity: sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==} engines: {node: '>= 0.4'} dependencies: hasown: 2.0.2 /is-data-view@1.0.1: resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} engines: {node: '>= 0.4'} dependencies: is-typed-array: 1.1.13 dev: true /is-date-object@1.0.5: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.2 dev: true /is-docker@2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} hasBin: true dev: false /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} dev: true /is-finalizationregistry@1.0.2: resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} dependencies: call-bind: 1.0.7 dev: true /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} /is-generator-function@1.0.10: resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.2 dev: true /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} dependencies: is-extglob: 2.1.1 dev: true /is-map@2.0.3: resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} engines: {node: '>= 0.4'} dev: true /is-negative-zero@2.0.3: resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} engines: {node: '>= 0.4'} dev: true /is-number-object@1.0.7: resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.2 dev: true /is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} /is-path-inside@3.0.3: resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} engines: {node: '>=8'} dev: true /is-plain-obj@2.1.0: resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} engines: {node: '>=8'} dev: true /is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 has-tostringtag: 1.0.2 dev: true /is-set@2.0.3: resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} engines: {node: '>= 0.4'} dev: true /is-shared-array-buffer@1.0.3: resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 dev: true /is-string@1.0.7: resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.2 dev: true /is-symbol@1.0.4: resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} engines: {node: '>= 0.4'} dependencies: has-symbols: 1.0.3 dev: true /is-typed-array@1.1.13: resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} engines: {node: '>= 0.4'} dependencies: which-typed-array: 1.1.15 dev: true /is-unicode-supported@0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} dev: true /is-weakmap@2.0.2: resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} engines: {node: '>= 0.4'} dev: true /is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: call-bind: 1.0.7 dev: true /is-weakset@2.0.3: resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 get-intrinsic: 1.2.4 dev: true /is-wsl@2.2.0: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} dependencies: is-docker: 2.2.1 dev: false /isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} /isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} dev: true /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true /iterator.prototype@1.1.2: resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} dependencies: define-properties: 1.2.1 get-intrinsic: 1.2.4 has-symbols: 1.0.3 reflect.getprototypeof: 1.0.6 set-function-name: 2.0.2 dev: true /jake@10.9.1: resolution: {integrity: sha512-61btcOHNnLnsOdtLgA5efqQWjnSi/vow5HbI7HMdKKWqvrKR1bLK3BPlJn9gcSaP2ewuamUSMB5XEy76KUIS2w==} engines: {node: '>=10'} hasBin: true dependencies: async: 3.2.5 chalk: 4.1.2 filelist: 1.0.4 minimatch: 3.1.2 dev: false /jest-diff@29.7.0: resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: chalk: 4.1.2 diff-sequences: 29.6.3 jest-get-type: 29.6.3 pretty-format: 29.7.0 /jest-get-type@29.6.3: resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} /jest-matcher-utils@29.7.0: resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: chalk: 4.1.2 jest-diff: 29.7.0 jest-get-type: 29.6.3 pretty-format: 29.7.0 /jest-message-util@29.7.0: resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@babel/code-frame': 7.24.7 '@jest/types': 29.6.3 '@types/stack-utils': 2.0.3 chalk: 4.1.2 graceful-fs: 4.2.11 micromatch: 4.0.7 pretty-format: 29.7.0 slash: 3.0.0 stack-utils: 2.0.6 /jest-util@29.7.0: resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 '@types/node': 20.12.12 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 picomatch: 2.3.1 /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} /js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true dependencies: argparse: 2.0.1 dev: true /js2xmlparser@4.0.2: resolution: {integrity: sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==} dependencies: xmlcreate: 2.0.4 dev: true /jsdoc@4.0.3: resolution: {integrity: sha512-Nu7Sf35kXJ1MWDZIMAuATRQTg1iIPdzh7tqJ6jjvaU/GfDf+qi5UV8zJR3Mo+/pYFvm8mzay4+6O5EWigaQBQw==} engines: {node: '>=12.0.0'} hasBin: true dependencies: '@babel/parser': 7.24.7 '@jsdoc/salty': 0.2.8 '@types/markdown-it': 14.1.1 bluebird: 3.7.2 catharsis: 0.9.0 escape-string-regexp: 2.0.0 js2xmlparser: 4.0.2 klaw: 3.0.0 markdown-it: 14.1.0 markdown-it-anchor: 8.6.7(@types/markdown-it@14.1.1)(markdown-it@14.1.0) marked: 4.3.0 mkdirp: 1.0.4 requizzle: 0.2.4 strip-json-comments: 3.1.1 underscore: 1.13.6 dev: true /jsesc@2.5.2: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} engines: {node: '>=4'} hasBin: true /json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} dev: true /json-parse-better-errors@1.0.2: resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} dev: true /json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} dev: false /json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} dev: true /json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} dev: true /json5@1.0.2: resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} hasBin: true dependencies: minimist: 1.2.8 dev: true /json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} hasBin: true /jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} dependencies: universalify: 2.0.1 optionalDependencies: graceful-fs: 4.2.11 dev: true /jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} dependencies: array-includes: 3.1.8 array.prototype.flat: 1.3.2 object.assign: 4.1.5 object.values: 1.2.0 dev: true /jszip@3.10.1: resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} dependencies: lie: 3.3.0 pako: 1.0.11 readable-stream: 2.3.8 setimmediate: 1.0.5 dev: false /just-extend@6.2.0: resolution: {integrity: sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==} dev: true /keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} dependencies: json-buffer: 3.0.1 dev: true /klaw-sync@6.0.0: resolution: {integrity: sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==} dependencies: graceful-fs: 4.2.11 dev: true /klaw@3.0.0: resolution: {integrity: sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==} dependencies: graceful-fs: 4.2.11 dev: true /levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} dependencies: prelude-ls: 1.2.1 type-check: 0.4.0 dev: true /lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} dependencies: immediate: 3.0.6 dev: false /lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} dev: false /linkify-it@5.0.0: resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} dependencies: uc.micro: 2.1.0 dev: true /load-json-file@5.3.0: resolution: {integrity: sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==} engines: {node: '>=6'} dependencies: graceful-fs: 4.2.11 parse-json: 4.0.0 pify: 4.0.1 strip-bom: 3.0.0 type-fest: 0.3.1 dev: true /load-json-file@7.0.1: resolution: {integrity: sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dev: true /locate-path@3.0.0: resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} engines: {node: '>=6'} dependencies: p-locate: 3.0.0 path-exists: 3.0.0 dev: true /locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} dependencies: p-locate: 5.0.0 dev: true /locate-path@7.2.0: resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: p-locate: 6.0.0 dev: true /lodash.get@4.4.2: resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} dev: true /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} /log-symbols@4.1.0: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} dependencies: chalk: 4.1.2 is-unicode-supported: 0.1.0 dev: true /loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true dependencies: js-tokens: 4.0.0 /lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} dependencies: tslib: 2.6.3 dev: true /lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: yallist: 3.1.1 /lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true dev: true /markdown-it-anchor@8.6.7(@types/markdown-it@14.1.1)(markdown-it@14.1.0): resolution: {integrity: sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==} peerDependencies: '@types/markdown-it': '*' markdown-it: '*' dependencies: '@types/markdown-it': 14.1.1 markdown-it: 14.1.0 dev: true /markdown-it@14.1.0: resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} hasBin: true dependencies: argparse: 2.0.1 entities: 4.5.0 linkify-it: 5.0.0 mdurl: 2.0.0 punycode.js: 2.3.1 uc.micro: 2.1.0 dev: true /marked@4.3.0: resolution: {integrity: sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==} engines: {node: '>= 12'} hasBin: true dev: true /md5@2.3.0: resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} dependencies: charenc: 0.0.2 crypt: 0.0.2 is-buffer: 1.1.6 dev: true /mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} dev: true /media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} dev: true /merge-descriptors@1.0.1: resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} dev: true /merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} dev: true /methods@1.1.2: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} dev: true /micromatch@4.0.7: resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} engines: {node: '>=8.6'} dependencies: braces: 3.0.3 picomatch: 2.3.1 /mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} dev: true /mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} dependencies: mime-db: 1.52.0 dev: true /mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} hasBin: true dev: true /min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} dev: true /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: brace-expansion: 1.1.11 /minimatch@5.0.1: resolution: {integrity: sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==} engines: {node: '>=10'} dependencies: brace-expansion: 2.0.1 dev: true /minimatch@5.1.6: resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} engines: {node: '>=10'} dependencies: brace-expansion: 2.0.1 dev: false /minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} dependencies: brace-expansion: 2.0.1 dev: true /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} /mkdirp@0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true dependencies: minimist: 1.2.8 /mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} hasBin: true dev: true /mkdirp@3.0.1: resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} engines: {node: '>=10'} hasBin: true dev: true /mocha-junit-reporter@2.2.1(mocha@10.5.1)(supports-color@9.4.0): resolution: {integrity: sha512-iDn2tlKHn8Vh8o4nCzcUVW4q7iXp7cC4EB78N0cDHIobLymyHNwe0XG8HEHHjc3hJlXm0Vy6zcrxaIhnI2fWmw==} peerDependencies: mocha: '>=2.2.5' dependencies: debug: 4.3.5(supports-color@9.4.0) md5: 2.3.0 mkdirp: 3.0.1 mocha: 10.5.1 strip-ansi: 6.0.1 xml: 1.0.1 transitivePeerDependencies: - supports-color dev: true /mocha@10.5.1: resolution: {integrity: sha512-eq5tEnaz2kM9ade8cuGJBMh5fBb9Ih/TB+ddlmPR+wLQmwLhUwa0ovqDlg7OTfKquW0BI7NUcNWX7DH8sC+3gw==} engines: {node: '>= 14.0.0'} hasBin: true dependencies: ansi-colors: 4.1.1 browser-stdout: 1.3.1 chokidar: 3.6.0 debug: 4.3.4(supports-color@8.1.1) diff: 5.0.0 escape-string-regexp: 4.0.0 find-up: 5.0.0 glob: 8.1.0 he: 1.2.0 js-yaml: 4.1.0 log-symbols: 4.1.0 minimatch: 5.0.1 ms: 2.1.3 serialize-javascript: 6.0.0 strip-json-comments: 3.1.1 supports-color: 8.1.1 workerpool: 6.2.1 yargs: 16.2.0 yargs-parser: 20.2.4 yargs-unparser: 2.0.0 dev: true /ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} dev: true /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} dev: true /multer@1.4.5-lts.1: resolution: {integrity: sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==} engines: {node: '>= 6.0.0'} dependencies: append-field: 1.0.0 busboy: 1.6.0 concat-stream: 1.6.2 mkdirp: 0.5.6 object-assign: 4.1.1 type-is: 1.6.18 xtend: 4.0.2 dev: true /natural-compare-lite@1.4.0: resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} dev: true /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true /negotiator@0.6.3: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} dev: true /nise@5.1.9: resolution: {integrity: sha512-qOnoujW4SV6e40dYxJOb3uvuoPHtmLzIk4TFo+j0jPJoC+5Z9xja5qH5JZobEPsa8+YYphMrOSwnrshEhG2qww==} dependencies: '@sinonjs/commons': 3.0.1 '@sinonjs/fake-timers': 11.2.2 '@sinonjs/text-encoding': 0.7.2 just-extend: 6.2.0 path-to-regexp: 6.2.2 dev: true /no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} dependencies: lower-case: 2.0.2 tslib: 2.6.3 dev: true /node-releases@2.0.14: resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} dev: true /object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} /object-inspect@1.13.2: resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} engines: {node: '>= 0.4'} dev: true /object-is@1.1.6: resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 dev: true /object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} dev: true /object.assign@4.1.5: resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 has-symbols: 1.0.3 object-keys: 1.1.1 dev: true /object.entries@1.1.8: resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-object-atoms: 1.0.0 dev: true /object.fromentries@2.0.8: resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-object-atoms: 1.0.0 dev: true /object.groupby@1.0.3: resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 dev: true /object.hasown@1.1.4: resolution: {integrity: sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==} engines: {node: '>= 0.4'} dependencies: define-properties: 1.2.1 es-abstract: 1.23.3 es-object-atoms: 1.0.0 dev: true /object.values@1.2.0: resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-object-atoms: 1.0.0 dev: true /on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} dependencies: ee-first: 1.1.1 dev: true /once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: wrappy: 1.0.2 /open@7.4.2: resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} engines: {node: '>=8'} dependencies: is-docker: 2.2.1 is-wsl: 2.2.0 dev: false /optimism@0.18.0: resolution: {integrity: sha512-tGn8+REwLRNFnb9WmcY5IfpOqeX2kpaYJ1s6Ae3mn12AeydLkR3j+jSCmVQFoXqU8D41PAJ1RG1rCRNWmNZVmQ==} dependencies: '@wry/caches': 1.0.1 '@wry/context': 0.7.4 '@wry/trie': 0.4.3 tslib: 2.6.3 dev: false /optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} dependencies: deep-is: 0.1.4 fast-levenshtein: 2.0.6 levn: 0.4.1 prelude-ls: 1.2.1 type-check: 0.4.0 word-wrap: 1.2.5 dev: true /p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} dependencies: p-try: 2.2.0 dev: true /p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} dependencies: yocto-queue: 0.1.0 dev: true /p-limit@4.0.0: resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: yocto-queue: 1.0.0 dev: true /p-locate@3.0.0: resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} engines: {node: '>=6'} dependencies: p-limit: 2.3.0 dev: true /p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} dependencies: p-limit: 3.1.0 dev: true /p-locate@6.0.0: resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: p-limit: 4.0.0 dev: true /p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} dev: true /pako@1.0.11: resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} dev: false /param-case@3.0.4: resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} dependencies: dot-case: 3.0.4 tslib: 2.6.3 dev: true /parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} dependencies: callsites: 3.1.0 /parse-json@4.0.0: resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} engines: {node: '>=4'} dependencies: error-ex: 1.3.2 json-parse-better-errors: 1.0.2 dev: true /parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} dependencies: '@babel/code-frame': 7.24.7 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 dev: false /parse-ms@4.0.0: resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} engines: {node: '>=18'} dev: false /parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} dev: true /pascal-case@3.1.2: resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} dependencies: no-case: 3.0.4 tslib: 2.6.3 dev: true /path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} dev: false /path-exists@3.0.0: resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} engines: {node: '>=4'} dev: true /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} dev: true /path-exists@5.0.0: resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dev: true /path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} /path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} dev: true /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} /path-to-regexp@0.1.7: resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} dev: true /path-to-regexp@6.2.2: resolution: {integrity: sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==} dev: true /path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} /picocolors@1.0.1: resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} /pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} dev: true /pkg-conf@3.1.0: resolution: {integrity: sha512-m0OTbR/5VPNPqO1ph6Fqbj7Hv6QU7gR/tQW40ZqrL1rjgCU85W6C1bJn0BItuJqnR98PWzw7Z8hHeChD1WrgdQ==} engines: {node: '>=6'} dependencies: find-up: 3.0.0 load-json-file: 5.3.0 dev: true /pkg-conf@4.0.0: resolution: {integrity: sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: find-up: 6.3.0 load-json-file: 7.0.1 dev: true /possible-typed-array-names@1.0.0: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} dev: true /prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} dev: true /prettier-linter-helpers@1.0.0: resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} engines: {node: '>=6.0.0'} dependencies: fast-diff: 1.3.0 dev: true /prettier@3.3.2: resolution: {integrity: sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==} engines: {node: '>=14'} hasBin: true dev: true /pretty-format@27.5.1: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: ansi-regex: 5.0.1 ansi-styles: 5.2.0 react-is: 17.0.2 dev: true /pretty-format@29.7.0: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/schemas': 29.6.3 ansi-styles: 5.2.0 react-is: 18.3.1 /pretty-ms@9.0.0: resolution: {integrity: sha512-E9e9HJ9R9NasGOgPaPE8VMeiPKAyWR5jcFpNnwIejslIhWqdqOrb2wShBsncMPUb+BcCd2OPYfh7p2W6oemTng==} engines: {node: '>=18'} dependencies: parse-ms: 4.0.0 dev: false /process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} /prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 react-is: 16.13.1 /proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} dependencies: forwarded: 0.2.0 ipaddr.js: 1.9.1 dev: true /punycode.js@2.3.1: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} dev: true /punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} dev: true /qs@6.11.0: resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} engines: {node: '>=0.6'} dependencies: side-channel: 1.0.6 dev: true /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true /rambda@7.5.0: resolution: {integrity: sha512-y/M9weqWAH4iopRd7EHDEQQvpFPHj1AA3oHozE9tfITHUtTR7Z9PSlIRRG2l1GuW7sefC1cXFfIcF+cgnShdBA==} dev: true /randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} dependencies: safe-buffer: 5.2.1 dev: true /range-parser@1.2.1: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} dev: true /raw-body@2.5.2: resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} engines: {node: '>= 0.8'} dependencies: bytes: 3.1.2 http-errors: 2.0.0 iconv-lite: 0.4.24 unpipe: 1.0.0 dev: true /react-dom@18.2.0(react@18.2.0): resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} peerDependencies: react: ^18.2.0 dependencies: loose-envify: 1.4.0 react: 18.2.0 scheduler: 0.23.2 /react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} /react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} dev: true /react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} /react-lifecycles-compat@3.0.4: resolution: {integrity: sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==} dev: false /react-modal@3.16.1(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-VStHgI3BVcGo7OXczvnJN7yT2TWHJPDXZWyI/a0ssFNhGZWsPmB8cF0z33ewDXq4VfYMO1vXgiv/g8Nj9NDyWg==} engines: {node: '>=8'} peerDependencies: react: ^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18 react-dom: ^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18 dependencies: exenv: 1.2.2 prop-types: 15.8.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-lifecycles-compat: 3.0.4 warning: 4.0.3 dev: false /react-router-dom@6.22.3(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-7ZILI7HjcE+p31oQvwbokjk6OA/bnFxrhJ19n82Ex9Ph8fNAq+Hm/7KchpMGlTgWhUxRHMMCut+vEtNpWpowKw==} engines: {node: '>=14.0.0'} peerDependencies: react: '>=16.8' react-dom: '>=16.8' dependencies: '@remix-run/router': 1.15.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-router: 6.22.3(react@18.2.0) dev: false /react-router@6.22.3(react@18.2.0): resolution: {integrity: sha512-dr2eb3Mj5zK2YISHK++foM9w4eBnO23eKnZEDs7c880P6oKbrjz/Svg9+nxqtHQK+oMW4OtjZca0RqPglXxguQ==} engines: {node: '>=14.0.0'} peerDependencies: react: '>=16.8' dependencies: '@remix-run/router': 1.15.3 react: 18.2.0 dev: false /react-transition-group@4.4.5(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} peerDependencies: react: '>=16.6.0' react-dom: '>=16.6.0' dependencies: '@babel/runtime': 7.24.7 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false /react@18.2.0: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} engines: {node: '>=0.10.0'} dependencies: loose-envify: 1.4.0 /readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} dependencies: core-util-is: 1.0.3 inherits: 2.0.4 isarray: 1.0.0 process-nextick-args: 2.0.1 safe-buffer: 5.1.2 string_decoder: 1.1.1 util-deprecate: 1.0.2 /readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} dependencies: picomatch: 2.3.1 dev: true /redent@3.0.0: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} dependencies: indent-string: 4.0.0 strip-indent: 3.0.0 dev: true /reflect.getprototypeof@1.0.6: resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-errors: 1.3.0 get-intrinsic: 1.2.4 globalthis: 1.0.4 which-builtin-type: 1.1.3 dev: true /regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} /regexp.prototype.flags@1.5.2: resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-errors: 1.3.0 set-function-name: 2.0.2 dev: true /regexpp@3.2.0: resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} engines: {node: '>=8'} dev: true /rehackt@0.1.0(@types/react@18.2.72)(react@18.2.0): resolution: {integrity: sha512-7kRDOuLHB87D/JESKxQoRwv4DzbIdwkAGQ7p6QKGdVlY1IZheUnVhlk/4UZlNUVxdAXpyxikE3URsG067ybVzw==} peerDependencies: '@types/react': '*' react: '*' peerDependenciesMeta: '@types/react': optional: true react: optional: true dependencies: '@types/react': 18.2.72 react: 18.2.0 dev: false /relateurl@0.2.7: resolution: {integrity: sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==} engines: {node: '>= 0.10'} dev: true /require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} /requizzle@0.2.4: resolution: {integrity: sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==} dependencies: lodash: 4.17.21 dev: true /resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} /resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} dev: true /resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true dependencies: is-core-module: 2.14.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 /resolve@2.0.0-next.5: resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} hasBin: true dependencies: is-core-module: 2.14.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 dev: true /response-iterator@0.2.6: resolution: {integrity: sha512-pVzEEzrsg23Sh053rmDUvLSkGXluZio0qu8VT6ukrYuvtjVfCbDZH9d6PGXb8HZfzdNZt8feXv/jvUzlhRgLnw==} engines: {node: '>=0.8'} dev: false /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} dev: true /rimraf@2.6.3: resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true dependencies: glob: 7.2.3 dev: false /rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true dependencies: glob: 7.2.3 dev: true /run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: queue-microtask: 1.2.3 dev: true /safe-array-concat@1.1.2: resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} engines: {node: '>=0.4'} dependencies: call-bind: 1.0.7 get-intrinsic: 1.2.4 has-symbols: 1.0.3 isarray: 2.0.5 dev: true /safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} /safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} dev: true /safe-regex-test@1.0.3: resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 es-errors: 1.3.0 is-regex: 1.1.4 dev: true /safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} dev: true /scheduler@0.23.2: resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} dependencies: loose-envify: 1.4.0 /semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true /semver@7.6.2: resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} engines: {node: '>=10'} hasBin: true dev: true /send@0.18.0(supports-color@9.4.0): resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} engines: {node: '>= 0.8.0'} dependencies: debug: 2.6.9(supports-color@9.4.0) depd: 2.0.0 destroy: 1.2.0 encodeurl: 1.0.2 escape-html: 1.0.3 etag: 1.8.1 fresh: 0.5.2 http-errors: 2.0.0 mime: 1.6.0 ms: 2.1.3 on-finished: 2.4.1 range-parser: 1.2.1 statuses: 2.0.1 transitivePeerDependencies: - supports-color dev: true /serialize-javascript@6.0.0: resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} dependencies: randombytes: 2.1.0 dev: true /serve-index@1.9.1(supports-color@9.4.0): resolution: {integrity: sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==} engines: {node: '>= 0.8.0'} dependencies: accepts: 1.3.8 batch: 0.6.1 debug: 2.6.9(supports-color@9.4.0) escape-html: 1.0.3 http-errors: 1.6.3 mime-types: 2.1.35 parseurl: 1.3.3 transitivePeerDependencies: - supports-color dev: true /serve-static@1.15.0(supports-color@9.4.0): resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} engines: {node: '>= 0.8.0'} dependencies: encodeurl: 1.0.2 escape-html: 1.0.3 parseurl: 1.3.3 send: 0.18.0(supports-color@9.4.0) transitivePeerDependencies: - supports-color dev: true /set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} dependencies: define-data-property: 1.1.4 es-errors: 1.3.0 function-bind: 1.1.2 get-intrinsic: 1.2.4 gopd: 1.0.1 has-property-descriptors: 1.0.2 dev: true /set-function-name@2.0.2: resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} engines: {node: '>= 0.4'} dependencies: define-data-property: 1.1.4 es-errors: 1.3.0 functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 dev: true /setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} dev: false /setprototypeof@1.1.0: resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==} dev: true /setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} dev: true /shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} dependencies: shebang-regex: 3.0.0 dev: true /shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} dev: true /showdown@2.1.0: resolution: {integrity: sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ==} hasBin: true dependencies: commander: 9.5.0 dev: true /side-channel@1.0.6: resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 es-errors: 1.3.0 get-intrinsic: 1.2.4 object-inspect: 1.13.2 dev: true /sinon@17.0.1: resolution: {integrity: sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==} dependencies: '@sinonjs/commons': 3.0.1 '@sinonjs/fake-timers': 11.2.2 '@sinonjs/samsam': 8.0.0 diff: 5.2.0 nise: 5.1.9 supports-color: 7.2.0 dev: true /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} /source-map-explorer@2.5.3: resolution: {integrity: sha512-qfUGs7UHsOBE5p/lGfQdaAj/5U/GWYBw2imEpD6UQNkqElYonkow8t+HBL1qqIl3CuGZx7n8/CQo4x1HwSHhsg==} engines: {node: '>=12'} hasBin: true dependencies: btoa: 1.2.1 chalk: 4.1.2 convert-source-map: 1.9.0 ejs: 3.1.10 escape-html: 1.0.3 glob: 7.2.3 gzip-size: 6.0.0 lodash: 4.17.21 open: 7.4.2 source-map: 0.7.4 temp: 0.9.4 yargs: 16.2.0 dev: false /source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} dependencies: buffer-from: 1.1.2 source-map: 0.6.1 dev: true /source-map@0.5.7: resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} engines: {node: '>=0.10.0'} dev: false /source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} dev: true /source-map@0.7.4: resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} engines: {node: '>= 8'} dev: false /stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} dependencies: escape-string-regexp: 2.0.0 /standard-engine@15.1.0: resolution: {integrity: sha512-VHysfoyxFu/ukT+9v49d4BRXIokFRZuH3z1VRxzFArZdjSCFpro6rEIU3ji7e4AoAtuSfKBkiOmsrDqKW5ZSRw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: get-stdin: 8.0.0 minimist: 1.2.8 pkg-conf: 3.1.0 xdg-basedir: 4.0.0 dev: true /statuses@1.5.0: resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} engines: {node: '>= 0.6'} dev: true /statuses@2.0.1: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} dev: true /stop-iteration-iterator@1.0.0: resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} engines: {node: '>= 0.4'} dependencies: internal-slot: 1.0.7 dev: true /streamsearch@1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} dev: true /string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} dependencies: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 /string.prototype.matchall@4.0.11: resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-errors: 1.3.0 es-object-atoms: 1.0.0 get-intrinsic: 1.2.4 gopd: 1.0.1 has-symbols: 1.0.3 internal-slot: 1.0.7 regexp.prototype.flags: 1.5.2 set-function-name: 2.0.2 side-channel: 1.0.6 dev: true /string.prototype.trim@1.2.9: resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-object-atoms: 1.0.0 dev: true /string.prototype.trimend@1.0.8: resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-object-atoms: 1.0.0 dev: true /string.prototype.trimstart@1.0.8: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-object-atoms: 1.0.0 dev: true /string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} dependencies: safe-buffer: 5.1.2 /strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} dependencies: ansi-regex: 5.0.1 /strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} dev: true /strip-indent@3.0.0: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} dependencies: min-indent: 1.0.1 dev: true /strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} dev: true /stylis@4.2.0: resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} dev: false /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} dependencies: has-flag: 3.0.0 /supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} dependencies: has-flag: 4.0.0 /supports-color@8.1.1: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} dependencies: has-flag: 4.0.0 dev: true /supports-color@9.4.0: resolution: {integrity: sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==} engines: {node: '>=12'} /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} /symbol-observable@4.0.0: resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} engines: {node: '>=0.10'} dev: false /synckit@0.8.8: resolution: {integrity: sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==} engines: {node: ^14.18.0 || >=16.0.0} dependencies: '@pkgr/core': 0.1.1 tslib: 2.6.3 dev: true /tapable@2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} dev: true /temp@0.9.4: resolution: {integrity: sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==} engines: {node: '>=6.0.0'} dependencies: mkdirp: 0.5.6 rimraf: 2.6.3 dev: false /terser@5.31.1: resolution: {integrity: sha512-37upzU1+viGvuFtBo9NPufCb9dwM0+l9hMxYyWfBA+fbwrPqNJAhbZ6W47bBFnZHKHTUBnMvi87434qq+qnxOg==} engines: {node: '>=10'} hasBin: true dependencies: '@jridgewell/source-map': 0.3.6 acorn: 8.12.0 commander: 2.20.3 source-map-support: 0.5.21 dev: true /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true /tmp@0.2.3: resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} engines: {node: '>=14.14'} dev: false /to-fast-properties@2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} /to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} dependencies: is-number: 7.0.0 /toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} dev: true /ts-invariant@0.10.3: resolution: {integrity: sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ==} engines: {node: '>=8'} dependencies: tslib: 2.6.3 dev: false /ts-standard@12.0.2(typescript@5.4.5): resolution: {integrity: sha512-XX2wrB9fKKTfBj4yD3ABm9iShzZcS2iWcPK8XzlBvuL20+wMiLgiz/k5tXgZwTaYq5wRhbks1Y9PelhujF/9ag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true peerDependencies: typescript: '*' dependencies: '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.5) eslint: 8.57.0 eslint-config-standard-jsx: 11.0.0(eslint-plugin-react@7.34.3)(eslint@8.57.0) eslint-config-standard-with-typescript: 23.0.0(@typescript-eslint/eslint-plugin@5.62.0)(eslint-plugin-import@2.29.1)(eslint-plugin-n@15.7.0)(eslint-plugin-promise@6.2.0)(eslint@8.57.0)(typescript@5.4.5) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.62.0)(eslint@8.57.0) eslint-plugin-n: 15.7.0(eslint@8.57.0) eslint-plugin-promise: 6.2.0(eslint@8.57.0) eslint-plugin-react: 7.34.3(eslint@8.57.0) minimist: 1.2.8 pkg-conf: 4.0.0 standard-engine: 15.1.0 typescript: 5.4.5 transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color dev: true /tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} dependencies: '@types/json5': 0.0.29 json5: 1.0.2 minimist: 1.2.8 strip-bom: 3.0.0 dev: true /tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} dev: true /tslib@2.6.3: resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} /tsutils@3.21.0(typescript@5.4.5): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.14.1 typescript: 5.4.5 dev: true /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} dependencies: prelude-ls: 1.2.1 dev: true /type-detect@4.0.8: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} dev: true /type-fest@0.20.2: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} dev: true /type-fest@0.3.1: resolution: {integrity: sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==} engines: {node: '>=6'} dev: true /type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} dependencies: media-typer: 0.3.0 mime-types: 2.1.35 dev: true /typed-array-buffer@1.0.2: resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 es-errors: 1.3.0 is-typed-array: 1.1.13 dev: true /typed-array-byte-length@1.0.1: resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 for-each: 0.3.3 gopd: 1.0.1 has-proto: 1.0.3 is-typed-array: 1.1.13 dev: true /typed-array-byte-offset@1.0.2: resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} engines: {node: '>= 0.4'} dependencies: available-typed-arrays: 1.0.7 call-bind: 1.0.7 for-each: 0.3.3 gopd: 1.0.1 has-proto: 1.0.3 is-typed-array: 1.1.13 dev: true /typed-array-length@1.0.6: resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 for-each: 0.3.3 gopd: 1.0.1 has-proto: 1.0.3 is-typed-array: 1.1.13 possible-typed-array-names: 1.0.0 dev: true /typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} dev: true /typescript@5.4.5: resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} engines: {node: '>=14.17'} hasBin: true dev: true /uc.micro@2.1.0: resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} dev: true /unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: call-bind: 1.0.7 has-bigints: 1.0.2 has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 dev: true /underscore@1.13.6: resolution: {integrity: sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==} dev: true /undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} /universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} dev: true /unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} dev: true /update-browserslist-db@1.0.16(browserslist@4.23.1): resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' dependencies: browserslist: 4.23.1 escalade: 3.1.2 picocolors: 1.0.1 /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: punycode: 2.3.1 dev: true /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} /utils-merge@1.0.1: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} dev: true /vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} dev: true /warning@4.0.3: resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} dependencies: loose-envify: 1.4.0 dev: false /which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} dependencies: is-bigint: 1.0.4 is-boolean-object: 1.1.2 is-number-object: 1.0.7 is-string: 1.0.7 is-symbol: 1.0.4 dev: true /which-builtin-type@1.1.3: resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==} engines: {node: '>= 0.4'} dependencies: function.prototype.name: 1.1.6 has-tostringtag: 1.0.2 is-async-function: 2.0.0 is-date-object: 1.0.5 is-finalizationregistry: 1.0.2 is-generator-function: 1.0.10 is-regex: 1.1.4 is-weakref: 1.0.2 isarray: 2.0.5 which-boxed-primitive: 1.0.2 which-collection: 1.0.2 which-typed-array: 1.1.15 dev: true /which-collection@1.0.2: resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} engines: {node: '>= 0.4'} dependencies: is-map: 2.0.3 is-set: 2.0.3 is-weakmap: 2.0.2 is-weakset: 2.0.3 dev: true /which-typed-array@1.1.15: resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} engines: {node: '>= 0.4'} dependencies: available-typed-arrays: 1.0.7 call-bind: 1.0.7 for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.2 dev: true /which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} hasBin: true dependencies: isexe: 2.0.0 dev: true /word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} dev: true /workerpool@6.2.1: resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==} dev: true /wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} dependencies: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} /ws@8.17.1: resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 utf-8-validate: '>=5.0.2' peerDependenciesMeta: bufferutil: optional: true utf-8-validate: optional: true dev: false /xdg-basedir@4.0.0: resolution: {integrity: sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==} engines: {node: '>=8'} dev: true /xml@1.0.1: resolution: {integrity: sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==} dev: true /xmlcreate@2.0.4: resolution: {integrity: sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==} dev: true /xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} dev: true /y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} /yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} /yaml@1.10.2: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} dev: false /yargs-parser@20.2.4: resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} engines: {node: '>=10'} dev: true /yargs-parser@20.2.9: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} engines: {node: '>=10'} /yargs-unparser@2.0.0: resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} engines: {node: '>=10'} dependencies: camelcase: 6.3.0 decamelize: 4.0.0 flat: 5.0.2 is-plain-obj: 2.1.0 dev: true /yargs@16.2.0: resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} engines: {node: '>=10'} dependencies: cliui: 7.0.4 escalade: 3.1.2 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 20.2.9 /yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} dev: true /yocto-queue@1.0.0: resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} engines: {node: '>=12.20'} dev: true /zen-observable-ts@1.2.5: resolution: {integrity: sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg==} dependencies: zen-observable: 0.8.15 dev: false /zen-observable@0.8.15: resolution: {integrity: sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==} dev: false selenium-selenium-4.23.0/.OLD_AUTHORS0000664000175000017500000000044414646203155016756 0ustar carstencarstenJoe Walnes Vyvyan Codd Zoltar - Knower of All Carlos Villela James Cooper Malcolm Rowe Mirko Nasato Marc Guillemot Alexis Vuillemin Noel Gordon David Wang Amitabh Saikia Jon Spalding James Strachen Rune Flobakk Michele Sama Muthu Kannan Terence Haddock Jean-Francois Roche Godefroid Chapelle selenium-selenium-4.23.0/MODULE.bazel0000664000175000017500000004214214646203155017137 0ustar carstencarstenmodule(name = "selenium") bazel_dep(name = "apple_rules_lint", version = "0.3.2") bazel_dep(name = "aspect_bazel_lib", version = "2.7.7") bazel_dep(name = "aspect_rules_esbuild", version = "0.20.1") bazel_dep(name = "aspect_rules_js", version = "1.42.3") bazel_dep(name = "aspect_rules_ts", version = "2.4.2") bazel_dep(name = "bazel_features", version = "1.13.0") bazel_dep(name = "bazel_skylib", version = "1.7.1") bazel_dep(name = "buildifier_prebuilt", version = "6.4.0") bazel_dep(name = "contrib_rules_jvm", version = "0.27.0") bazel_dep(name = "platforms", version = "0.0.10") # Required for the closure rules bazel_dep(name = "protobuf", version = "21.7", dev_dependency = True, repo_name = "com_google_protobuf") # Required for rules_rust to import the crates properly bazel_dep(name = "rules_cc", version = "0.0.9", dev_dependency = True) bazel_dep(name = "rules_dotnet", version = "0.15.1") bazel_dep(name = "rules_java", version = "7.6.3") bazel_dep(name = "rules_jvm_external", version = "6.1") bazel_dep(name = "rules_nodejs", version = "6.2.0") bazel_dep(name = "rules_oci", version = "1.7.6") bazel_dep(name = "rules_pkg", version = "0.10.1") bazel_dep(name = "rules_python", version = "0.33.0") bazel_dep(name = "rules_proto", version = "6.0.0") bazel_dep(name = "rules_ruby", version = "0.11.0") linter = use_extension("@apple_rules_lint//lint:extensions.bzl", "linter") linter.configure( name = "java-spotbugs", config = "//java:spotbugs-config", ) linter.configure( name = "rust-rustfmt", config = "//rust:enable-rustfmt", ) linter.register(name = "rust-rustfmt") node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node") node.toolchain(node_version = "20.9.0") pnpm = use_extension("@aspect_rules_js//npm:extensions.bzl", "pnpm", dev_dependency = True) use_repo(pnpm, "pnpm") npm = use_extension("@aspect_rules_js//npm:extensions.bzl", "npm") npm.npm_translate_lock( name = "npm", data = [ "@//:package.json", "@//:pnpm-workspace.yaml", "@//javascript/grid-ui:package.json", "@//javascript/node/selenium-webdriver:package.json", ], generate_bzl_library_targets = True, npmrc = "//:.npmrc", pnpm_lock = "//:pnpm-lock.yaml", update_pnpm_lock = True, verify_node_modules_ignored = "//:.bazelignore", ) use_repo(npm, "npm") rules_ts_ext = use_extension( "@aspect_rules_ts//ts:extensions.bzl", "ext", dev_dependency = True, ) rules_ts_ext.deps( ts_version = "4.9.5", ) use_repo(rules_ts_ext, "npm_typescript") esbuild = use_extension("@aspect_rules_esbuild//esbuild:extensions.bzl", "esbuild") esbuild.toolchain(esbuild_version = "0.19.9") use_repo(esbuild, "esbuild_toolchains") register_toolchains("@esbuild_toolchains//:all") dotnet = use_extension("@rules_dotnet//dotnet:extensions.bzl", "dotnet") dotnet.toolchain(dotnet_version = "7.0.400") use_repo(dotnet, "dotnet_toolchains") selenium_paket = use_extension("//dotnet:paket.nuget_extension.bzl", "nuget_extension") use_repo(selenium_paket, "paket.nuget") register_toolchains("@dotnet_toolchains//:all") oci = use_extension("@rules_oci//oci:extensions.bzl", "oci") oci.pull( name = "java_image_base", digest = "sha256:161a1d97d592b3f1919801578c3a47c8e932071168a96267698f4b669c24c76d", image = "gcr.io/distroless/java17", ) oci.pull( name = "firefox_standalone", digest = "sha256:b6d8279268b3183d0d33e667e82fec1824298902f77718764076de763673124f", image = "index.docker.io/selenium/standalone-firefox", ) oci.pull( name = "chrome_standalone", digest = "sha256:1b809a961a0a77787a7cccac74ddc5570b7e89747f925b8469ddb9a6624d4ece", image = "index.docker.io/selenium/standalone-chrome", ) use_repo(oci, "chrome_standalone", "firefox_standalone", "java_image_base") python = use_extension("@rules_python//python/extensions:python.bzl", "python") python.toolchain( is_default = True, python_version = "3.8", ) python.toolchain(python_version = "3.9") python.toolchain(python_version = "3.10") python.toolchain(python_version = "3.11") use_repo(python, "pythons_hub") pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip") [ pip.parse( hub_name = "py_dev_requirements", python_version = version, requirements_lock = "//py:requirements_lock.txt", ) for version in [ "3.8", "3.9", "3.10", "3.11", ] ] use_repo(pip, "py_dev_requirements") register_toolchains("@pythons_hub//:all") # https://github.com/bazelbuild/rules_jvm_external/pull/1079 archive_override( module_name = "rules_jvm_external", integrity = "sha256-yS8Qes1PLbYbe10b1WSgl0Auqn/1Wlxg8O3wSr7a/Sg=", patch_strip = 1, patches = ["//java:rules_jvm_external_javadoc.patch"], strip_prefix = "rules_jvm_external-f572a26116c7ef71d8842dd056c2605782f7be8d", urls = ["https://github.com/bazelbuild/rules_jvm_external/archive/f572a26116c7ef71d8842dd056c2605782f7be8d.tar.gz"], ) java_toolchains = use_extension("@rules_java//java:extensions.bzl", "toolchains") use_repo( java_toolchains, "remote_java_tools", "remote_java_tools_darwin_arm64", "remote_java_tools_darwin_x86_64", "remote_java_tools_linux", "remote_java_tools_windows", "remotejdk17_linux", "remotejdk17_linux_s390x", "remotejdk17_macos", "remotejdk17_macos_aarch64", "remotejdk17_win", "remotejdk17_win_arm64", ) maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven") maven.install( name = "maven", artifacts = [ "com.beust:jcommander:1.82", "com.github.javaparser:javaparser-core:3.26.1", "com.github.spotbugs:spotbugs:4.8.6", "com.github.stephenc.jcip:jcip-annotations:1.0-1", "com.google.code.gson:gson:2.11.0", "com.google.guava:guava:33.2.1-jre", "com.google.auto:auto-common:1.2.2", "com.google.auto.service:auto-service:1.1.1", "com.google.auto.service:auto-service-annotations:1.1.1", "com.google.googlejavaformat:google-java-format:jar:1.22.0", "com.graphql-java:graphql-java:20.2", "com.graphql-java:java-dataloader:3.2.0", "dev.failsafe:failsafe:3.3.2", "io.grpc:grpc-context:1.65.1", "io.lettuce:lettuce-core:6.3.2.RELEASE", "io.netty:netty-buffer:4.1.111.Final", "io.netty:netty-codec-http:4.1.111.Final", "io.netty:netty-codec-http2:4.1.111.Final", "io.netty:netty-common:4.1.111.Final", "io.netty:netty-handler:4.1.111.Final", "io.netty:netty-handler-proxy:4.1.111.Final", "io.netty:netty-transport:4.1.111.Final", "io.opentelemetry:opentelemetry-api:1.40.0", "io.opentelemetry:opentelemetry-context:1.40.0", "io.opentelemetry:opentelemetry-exporter-logging:1.40.0", "io.opentelemetry:opentelemetry-sdk:1.40.0", "io.opentelemetry:opentelemetry-sdk-common:1.40.0", "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure:1.40.0", "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi:1.40.0", "io.opentelemetry:opentelemetry-sdk-testing:1.40.0", "io.opentelemetry:opentelemetry-sdk-trace:1.40.0", "io.opentelemetry.semconv:opentelemetry-semconv:1.25.0-alpha", "io.ous:jtoml:2.0.0", "it.ozimov:embedded-redis:0.7.3", "net.bytebuddy:byte-buddy:1.14.18", "org.htmlunit:htmlunit-core-js:4.3.0", "org.apache.commons:commons-exec:1.4.0", "org.apache.logging.log4j:log4j-core:2.23.1", "org.assertj:assertj-core:3.26.3", "org.bouncycastle:bcpkix-jdk18on:1.78.1", "org.eclipse.mylyn.github:org.eclipse.egit.github.core:2.1.5", "org.hsqldb:hsqldb:2.7.3", "org.junit.jupiter:junit-jupiter-api:5.10.3", "org.junit.jupiter:junit-jupiter-engine:5.10.3", "org.junit.jupiter:junit-jupiter-params:5.10.3", "org.junit.platform:junit-platform-launcher:1.10.3", "org.junit.platform:junit-platform-reporting:1.10.3", "org.junit.platform:junit-platform-commons:1.10.3", "org.junit.platform:junit-platform-engine:1.10.3", "org.mockito:mockito-core:5.12.0", "org.redisson:redisson:3.33.0", "org.slf4j:slf4j-api:2.0.13", "org.slf4j:slf4j-jdk14:2.0.13", "org.zeromq:jeromq:0.6.0", ], excluded_artifacts = [ "org.hamcrest:hamcrest-all", # Replaced by hamcrest 2 "org.hamcrest:hamcrest-core", "io.netty:netty-all", # Depend on the actual things you need ], fail_if_repin_required = True, fail_on_missing_checksum = True, fetch_sources = True, lock_file = "//java:maven_install.json", repositories = [ "https://repo1.maven.org/maven2", ], strict_visibility = True, ) use_repo(maven, "maven", "unpinned_maven") ruby = use_extension("@rules_ruby//ruby:extensions.bzl", "ruby") ruby.toolchain( name = "ruby", version_file = "//:rb/.ruby-version", ) ruby.bundle_fetch( name = "bundle", srcs = [ "//:rb/lib/selenium/devtools/version.rb", "//:rb/lib/selenium/webdriver/version.rb", "//:rb/selenium-devtools.gemspec", "//:rb/selenium-webdriver.gemspec", ], gem_checksums = { "abbrev-0.1.2": "ad1b4eaaaed4cb722d5684d63949e4bde1d34f2a95e20db93aecfe7cbac74242", "activesupport-7.1.3.2": "ad8445b7ae4a6d3acc5f88c8c5f437eb0b54062032aaf44856c7b6d3855b8b2e", "addressable-2.8.6": "798f6af3556641a7619bad1dce04cdb6eb44b0216a991b0396ea7339276f2b47", "ast-2.4.2": "1e280232e6a33754cde542bc5ef85520b74db2aac73ec14acef453784447cc12", "base64-0.2.0": "0f25e9b21a02a0cc0cea8ef92b2041035d39350946e8789c562b2d1a3da01507", "bigdecimal-3.1.7": "e799b369a0005fc6d62eed7ef19139ac9bc319cc51470c637b9dcdf593600133", "bigdecimal-3.1.7-java": "955f5c7aa90136874b494655e42ed70d81382abb0f49f1b42f374a1660e33c63", "concurrent-ruby-1.2.3": "82fdd3f8a0816e28d513e637bb2b90a45d7b982bdf4f3a0511722d2e495801e2", "connection_pool-2.4.1": "0f40cf997091f1f04ff66da67eabd61a9fe0d4928b9a3645228532512fab62f4", "crack-1.0.0": "c83aefdb428cdc7b66c7f287e488c796f055c0839e6e545fec2c7047743c4a49", "csv-3.3.0": "0bbd1defdc31134abefed027a639b3723c2753862150f4c3ee61cab71b20d67d", "debug-1.9.2": "48e026c0852c7a10c60263e2e527968308958e266231e36d64e3efcabec7e7fc", "diff-lcs-1.5.1": "273223dfb40685548436d32b4733aa67351769c7dea621da7d9dd4813e63ddfe", "drb-2.2.1": "e9d472bf785f558b96b25358bae115646da0dbfd45107ad858b0bc0d935cb340", "ffi-1.16.3": "6d3242ff10c87271b0675c58d68d3f10148fabc2ad6da52a18123f06078871fb", "ffi-1.16.3-java": "6f107fcd7c96f9c96f7e57db749b99502cc2f65665f7b2241d087a8f8c01d42c", "ffi-1.16.3-x64-mingw32": "6ec709011e3955e97033fa77907a8ab89a9150137d4c45c82c77399b909c9259", "fileutils-1.7.2": "36a0fb324218263e52b486ad7408e9a295378fe8edc9fd343709e523c0980631", "git-1.19.1": "b0a422d9f6517353c48a330d6114de4db9e0c82dbe7202964a1d9f1fbc827d70", "hashdiff-1.1.0": "b5465f0e7375f1ee883f53a766ece4dbc764b7674a7c5ffd76e79b2f5f6fc9c9", "i18n-1.14.4": "c7deedead0866ea9102975a4eab7968f53de50793a0c211a37808f75dd187551", "io-console-0.7.2": "f0dccff252f877a4f60d04a4dc6b442b185ebffb4b320ab69212a92b48a7a221", "io-console-0.7.2-java": "73aa382f8832b116613ceaf57b8ff5bf73dfedcaf39f0aa5420e10f63a4543ed", "irb-1.12.0": "07634937fbb7d28d07e46da50d0aa43b4d2f7258174d08de4e32dfb57c10539d", "jar-dependencies-0.4.1": "b2df2f1ecbff15334ce20ea7fdd5b8d8161faab67761ff72c7647d728e40d387", "json-2.7.2": "1898b5cbc81cd36c0fd4d0b7ad2682c39fb07c5ff682fc6265f678f550d4982c", "json-2.7.2-java": "138e3038b5361b3d06ee2e8aa2be00bed0d0de4ef5f1553fc5935e5b93aca7ee", "language_server-protocol-3.17.0.3": "3d5c58c02f44a20d972957a9febe386d7e7468ab3900ce6bd2b563dd910c6b3f", "listen-3.9.0": "db9e4424e0e5834480385197c139cb6b0ae0ef28cc13310cfd1ca78377d59c67", "logger-1.6.0": "0ab7c120262dd8de2a18cb8d377f1f318cbe98535160a508af9e7710ff43ef3e", "minitest-5.22.3": "ea84676290cb5e2b4f31f25751af6050aa90d3e43e4337141c3e3e839611981e", "mutex_m-0.2.0": "b6ef0c6c842ede846f2ec0ade9e266b1a9dac0bc151682b04835e8ebd54840d5", "parallel-1.24.0": "5bf38efb9b37865f8e93d7a762727f8c5fc5deb19949f4040c76481d5eee9397", "parser-3.3.0.5": "7748313e505ca87045dc0465c776c802043f777581796eb79b1654c5d19d2687", "psych-5.1.2": "337322f58fc2bf24827d2b9bd5ab595f6a72971867d151bb39980060ea40a368", "psych-5.1.2-java": "1dd68dc609eddbc884e6892e11da942e16f7256bd30ebde9d35449d43043a6fe", "public_suffix-5.0.5": "72c340218bb384610536919988705cc29e09749c0021fd7005f715c7e5dfc493", "racc-1.7.3": "b785ab8a30ec43bce073c51dbbe791fd27000f68d1c996c95da98bf685316905", "racc-1.7.3-java": "b2ad737e788cfa083263ce7c9290644bb0f2c691908249eb4f6eb48ed2815dbf", "rack-2.2.9": "fd6301a97a1c1e955e68f85c861fcb1cde6145a32c532e1ea321a72ff8cc4042", "rainbow-3.1.1": "039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a", "rake-13.2.1": "46cb38dae65d7d74b6020a4ac9d48afed8eb8149c040eccf0523bec91907059d", "rb-fsevent-0.11.2": "43900b972e7301d6570f64b850a5aa67833ee7d87b458ee92805d56b7318aefe", "rb-inotify-0.10.1": "050062d4f31d307cca52c3f6a7f4b946df8de25fc4bd373e1a5142e41034a7ca", "rbs-3.4.4": "1376d2604a00832641bb47521595e63a1c0d1cc241ded383ba48ddb4396de5a8", "rchardet-1.8.0": "693acd5253d5ade81a51940697955f6dd4bb2f0d245bda76a8e23deec70a52c7", "rdoc-6.6.3.1": "39f7b749229ab5ad9d21c81586151c1dd7a549fa8be4070ee09b524f9c656345", "regexp_parser-2.9.0": "81a00ba141cec0d4b4bf58cb80cd9193e5180836d3fa6ef623f7886d3ba8bdd9", "reline-0.5.3": "2c46747a1dfd03e100f0666d8a374cf2930c3e734298af9b39e5fe8d35b42035", "rexml-3.2.6": "e0669a2d4e9f109951cb1fde723d8acd285425d81594a2ea929304af50282816", "rspec-3.13.0": "d490914ac1d5a5a64a0e1400c1d54ddd2a501324d703b8cfe83f458337bab993", "rspec-core-3.13.0": "557792b4e88da883d580342b263d9652b6a10a12d5bda9ef967b01a48f15454c", "rspec-expectations-3.13.0": "621d48c62262f955421eaa418130744760802cad47e781df70dba4d9f897102e", "rspec-mocks-3.13.0": "735a891215758d77cdb5f4721fffc21078793959d1f0ee4a961874311d9b7f66", "rspec-support-3.13.1": "48877d4f15b772b7538f3693c22225f2eda490ba65a0515c4e7cf6f2f17de70f", "rubocop-1.63.3": "17a31f16658f2fbb20bc7bcb4a841a06f7368da4f3be8a50365ad61e658d5f44", "rubocop-ast-1.31.2": "7c206fb094553779923eca862aceece3913ce384f1bf85730208228e884578ec", "rubocop-capybara-2.20.0": "2a6844b942921f230ee3ab8c94fe77f41a9406096a140245270c0e11624bb938", "rubocop-factory_bot-2.25.1": "62751bde7af789878b8a31cbd2a82e69515ce7b23a2ad1820cb0fcc3e0150134", "rubocop-performance-1.21.0": "ec54fa8991c2d538af7bc958361d63bdb3df2e53032da393e9903ea5e4f74a9a", "rubocop-rspec-2.29.1": "534ee81a3006e7379ec6203687ef7c06ca1d137b7d6d67c2777b680b1ce82e13", "rubocop-rspec_rails-2.28.3": "9769f2077cca8af2269193ba0450e0317ae1827a132c19149fdbeecaaca32818", "ruby-progressbar-1.13.0": "80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33", "rubyzip-2.3.2": "3f57e3935dc2255c414484fbf8d673b4909d8a6a57007ed754dde39342d2373f", "securerandom-0.3.1": "98f0450c0ea46d2f9a4b6db4f391dbd83dc08049592eada155739f40e0341bde", "steep-1.5.3": "7c6302a4d5932d0a46176ebc79766e52b853c223a85525aa2f8911e345123b85", "stringio-3.1.0": "c1f6263ae03a15025e51194ab19b06b15e06adcaaedb7f5f6c06ab60f5d67718", "strscan-3.1.0": "01b8a81d214fbf7b5308c6fb51b5972bbfc4a6aa1f166fd3618ba97e0fcd5555", "strscan-3.1.0-java": "8645aa76e017e21764c6df572d2d79fcc1672284014f5bdbd806278cdbcd11b0", "terminal-table-3.0.2": "f951b6af5f3e00203fb290a669e0a85c5dd5b051b3b023392ccfd67ba5abae91", "tzinfo-2.0.6": "8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b", "unicode-display_width-2.5.0": "7e7681dcade1add70cb9fda20dd77f300b8587c81ebbd165d14fd93144ff0ab4", "webmock-3.23.0": "100787435c1f556129a238c11cc7cbee38cb9c2864709c6a0dcdcf822545f31f", "webrick-1.8.1": "19411ec6912911fd3df13559110127ea2badd0c035f7762873f58afc803e158f", "websocket-1.2.10": "2cc1a4a79b6e63637b326b4273e46adcddf7871caa5dc5711f2ca4061a629fa8", "yard-0.9.36": "5505736c1b00c926f71053a606ab75f02070c5960d0778b901fe9d8b0a470be4", }, gemfile = "//:rb/Gemfile", gemfile_lock = "//:rb/Gemfile.lock", ) use_repo(ruby, "bundle", "ruby", "ruby_toolchains") register_toolchains("@ruby_toolchains//:all") selenium_manager_artifacts = use_extension("//common:selenium_manager.bzl", "selenium_manager_artifacts") use_repo( selenium_manager_artifacts, "download_sm_linux", "download_sm_macos", "download_sm_windows", ) pin_browsers_extension = use_extension("//common:repositories.bzl", "pin_browsers_extension") use_repo( pin_browsers_extension, "linux_beta_firefox", "linux_chrome", "linux_chromedriver", "linux_edge", "linux_edgedriver", "linux_firefox", "linux_geckodriver", "mac_beta_firefox", "mac_chrome", "mac_chromedriver", "mac_edge", "mac_edgedriver", "mac_firefox", "mac_geckodriver", ) local_drivers = use_repo_rule("//common/private:drivers.bzl", "local_drivers") local_drivers(name = "local_drivers") selenium-selenium-4.23.0/NOTICE0000664000175000017500000000013114646203155016027 0ustar carstencarstenCopyright 2011-2024 Software Freedom Conservancy Copyright 2004-2011 Selenium committers selenium-selenium-4.23.0/pytest.ini0000664000175000017500000000107714646203155017166 0ustar carstencarsten[pytest] console_output_style = progress faulthandler_timeout = 60 log_cli = True trio_mode = true markers = xfail_chrome: Tests expected to fail in Chrome xfail_edge: Tests expected to fail in Edge xfail_firefox: Tests expected to fail in Firefox xfail_ie: Tests expected to fail in IE xfail_remote: Tests expected to fail with Remote webdriver xfail_safari: Tests expected to fail in Safari xfail_webkitgtk: Tests expected to fail in webkitgtk no_driver_after_test: If there are no drivers after the test it will create a new one. addopts = selenium-selenium-4.23.0/mypy.ini0000664000175000017500000000371014646203155016630 0ustar carstencarsten; The aim in future here is we would be able to turn (most) of these flags on, however the typing technical ; debt is quite colossal right now. For now we should maybe get everything working with the config here ; then look at going after partially or completely untyped defs as a phase-2. [mypy] files = selenium ; warn about per-module sections in the config file that do not match any files processed. warn_unused_configs = True ; disallows subclassing of typing.Any. disallow_subclassing_any = False ; disallow usage of generic types that do not specify explicit type parameters. disallow_any_generics = False ; disallow calling functions without type annotations from functions that have type annotations. disallow_untyped_calls = False ; disallow defining functions without type annotations or with incomplete annotations. disallow_untyped_defs = False ; disallow defining functions with incomplete type annotations. disallow_incomplete_defs = False ; type-checks the interior of functions without type annotations. check_untyped_defs = False ; reports an error whenever a function with type annotations is decorated with a decorator without annotations. disallow_untyped_decorators = False ; changes the treatment of arguments with a default value of None by not implicitly making their type `typing.Optional`. no_implicit_optional = False ; warns about casting an expression to it's inferred type. warn_redundant_casts = True ; warns about unneeded `# type: ignore` comments. warn_unused_ignores = True ; warns when returning a value with typing.Any from a function with a non typing.Any return type. warn_return_any = False ; Shows a warning when encountering any code inferred to be unreachable after performing type analysis. warn_unreachable = False [mypy-trio_websocket] ; suppress error messages about imports that cannot be resolved. ignore_missing_imports = True [mypy-_winreg] ; suppress error messages about imports that cannot be resolved. ignore_missing_imports = True selenium-selenium-4.23.0/release-selenium.py0000664000175000017500000000166514646203155020751 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import sys from twine import cli def main(): cli.configure_output() return cli.dispatch(sys.argv[1:]) if __name__ == "__main__": sys.exit(main()) selenium-selenium-4.23.0/test/0000775000175000017500000000000014646203155016107 5ustar carstencarstenselenium-selenium-4.23.0/test/__init__.py0000664000175000017500000000142314646203155020220 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.23.0/test/selenium/0000775000175000017500000000000014646203155017730 5ustar carstencarstenselenium-selenium-4.23.0/test/selenium/__init__.py0000664000175000017500000000142314646203155022041 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.23.0/test/selenium/webdriver/0000775000175000017500000000000014646203155021721 5ustar carstencarstenselenium-selenium-4.23.0/test/selenium/webdriver/firefox/0000775000175000017500000000000014646203155023363 5ustar carstencarstenselenium-selenium-4.23.0/test/selenium/webdriver/firefox/ff_installs_addons_tests.py0000664000175000017500000001062214646203155031014 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import os import zipfile from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait extensions = os.path.abspath("../../../../../../test/extensions/") def test_install_uninstall_signed_addon_xpi(driver, pages): extension = os.path.join(extensions, "webextensions-selenium-example.xpi") id = driver.install_addon(extension) assert id == "webextensions-selenium-example-v3@example.com" pages.load("blank.html") injected = WebDriverWait(driver, timeout=2).until( lambda dr: dr.find_element(By.ID, "webextensions-selenium-example") ) assert injected.text == "Content injected by webextensions-selenium-example" driver.uninstall_addon(id) driver.refresh() assert len(driver.find_elements(By.ID, "webextensions-selenium-example")) == 0 def test_install_uninstall_signed_addon_zip(driver, pages): extension = os.path.join(extensions, "webextensions-selenium-example.zip") id = driver.install_addon(extension) assert id == "webextensions-selenium-example-v3@example.com" pages.load("blank.html") injected = WebDriverWait(driver, timeout=2).until( lambda dr: dr.find_element(By.ID, "webextensions-selenium-example") ) assert injected.text == "Content injected by webextensions-selenium-example" driver.uninstall_addon(id) driver.refresh() assert len(driver.find_elements(By.ID, "webextensions-selenium-example")) == 0 def test_install_uninstall_unsigned_addon_zip(driver, pages): extension = os.path.join(extensions, "webextensions-selenium-example-unsigned.zip") id = driver.install_addon(extension, temporary=True) assert id == "webextensions-selenium-example-v3@example.com" pages.load("blank.html") injected = WebDriverWait(driver, timeout=2).until( lambda dr: dr.find_element(By.ID, "webextensions-selenium-example") ) assert injected.text == "Content injected by webextensions-selenium-example" driver.uninstall_addon(id) driver.refresh() assert len(driver.find_elements(By.ID, "webextensions-selenium-example")) == 0 def test_install_uninstall_signed_addon_dir(driver, pages): zip = os.path.join(extensions, "webextensions-selenium-example.zip") target = os.path.join(extensions, "webextensions-selenium-example") with zipfile.ZipFile(zip, "r") as zip_ref: zip_ref.extractall(target) id = driver.install_addon(target) assert id == "webextensions-selenium-example-v3@example.com" pages.load("blank.html") injected = WebDriverWait(driver, timeout=2).until( lambda dr: dr.find_element(By.ID, "webextensions-selenium-example") ) assert injected.text == "Content injected by webextensions-selenium-example" driver.uninstall_addon(id) driver.refresh() assert len(driver.find_elements(By.ID, "webextensions-selenium-example")) == 0 def test_install_uninstall_unsigned_addon_dir(driver, pages): zip = os.path.join(extensions, "webextensions-selenium-example-unsigned.zip") target = os.path.join(extensions, "webextensions-selenium-example-unsigned") with zipfile.ZipFile(zip, "r") as zip_ref: zip_ref.extractall(target) id = driver.install_addon(target, temporary=True) assert id == "webextensions-selenium-example-v3@example.com" pages.load("blank.html") injected = WebDriverWait(driver, timeout=2).until( lambda dr: dr.find_element(By.ID, "webextensions-selenium-example") ) assert injected.text == "Content injected by webextensions-selenium-example" driver.uninstall_addon(id) driver.refresh() assert len(driver.find_elements(By.ID, "webextensions-selenium-example")) == 0 selenium-selenium-4.23.0/test/selenium/webdriver/firefox/__init__.py0000664000175000017500000000142314646203155025474 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.23.0/test/selenium/webdriver/firefox/ff_takes_full_page_screenshots_tests.py0000664000175000017500000000230614646203155033400 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import base64 import imghdr def test_get_full_page_screenshot_as_base64(driver, pages): pages.load("simpleTest.html") result = base64.b64decode(driver.get_full_page_screenshot_as_base64()) assert imghdr.what("", result) == "png" def test_get_full_page_screenshot_as_png(driver, pages): pages.load("simpleTest.html") result = driver.get_full_page_screenshot_as_png() assert imghdr.what("", result) == "png" selenium-selenium-4.23.0/test/selenium/webdriver/firefox/firefox_service_tests.py0000664000175000017500000000355214646203155030346 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import os import subprocess from selenium.webdriver import Firefox from selenium.webdriver.firefox.service import Service def test_log_output_as_filename() -> None: log_file = "geckodriver.log" service = Service(log_output=log_file) try: driver = Firefox(service=service) with open(log_file) as fp: assert "geckodriver\tINFO\tListening" in fp.readline() finally: driver.quit() os.remove(log_file) def test_log_output_as_file() -> None: log_name = "geckodriver.log" log_file = open(log_name, "w", encoding="utf-8") service = Service(log_output=log_file) try: driver = Firefox(service=service) with open(log_name) as fp: assert "geckodriver\tINFO\tListening" in fp.readline() finally: driver.quit() log_file.close() os.remove(log_name) def test_log_output_as_stdout(capfd) -> None: service = Service(log_output=subprocess.STDOUT) driver = Firefox(service=service) out, err = capfd.readouterr() assert "geckodriver\tINFO\tListening" in out driver.quit() selenium-selenium-4.23.0/test/selenium/webdriver/firefox/conftest.py0000664000175000017500000000164414646203155025567 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver import Firefox @pytest.fixture def driver(): driver = Firefox() yield driver driver.quit() selenium-selenium-4.23.0/test/selenium/webdriver/remote/0000775000175000017500000000000014646203155023214 5ustar carstencarstenselenium-selenium-4.23.0/test/selenium/webdriver/remote/__init__.py0000664000175000017500000000142314646203155025325 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.23.0/test/selenium/webdriver/remote/remote_connection_tests.py0000664000175000017500000000203314646203155030520 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import base64 import imghdr def test_browser_specific_method(driver, pages): pages.load("simpleTest.html") screenshot = driver.execute("FULL_PAGE_SCREENSHOT")["value"] result = base64.b64decode(screenshot) assert imghdr.what("", result) == "png" selenium-selenium-4.23.0/test/selenium/webdriver/remote/remote_downloads_tests.py0000664000175000017500000000370414646203155030361 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import os import tempfile from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait def test_get_downloadable_files(driver, pages): _browser_downloads(driver, pages) file_names = driver.get_downloadable_files() assert "file_1.txt" in file_names assert "file_2.jpg" in file_names def test_download_file(driver, pages): _browser_downloads(driver, pages) file_name = driver.get_downloadable_files()[0] with tempfile.TemporaryDirectory() as target_directory: driver.download_file(file_name, target_directory) target_file = os.path.join(target_directory, file_name) with open(target_file, "r") as file: assert "Hello, World!" in file.read() def test_delete_downloadable_files(driver, pages): _browser_downloads(driver, pages) driver.delete_downloadable_files() assert not driver.get_downloadable_files() def _browser_downloads(driver, pages): pages.load("downloads/download.html") driver.find_element(By.ID, "file-1").click() driver.find_element(By.ID, "file-2").click() WebDriverWait(driver, 3).until(lambda d: "file_2.jpg" in d.get_downloadable_files()) selenium-selenium-4.23.0/test/selenium/webdriver/remote/remote_hub_connection.py0000664000175000017500000000222714646203155030141 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest import urllib3 from selenium import webdriver def test_command_executor_ssl_certificate_is_verified(): with pytest.raises(urllib3.exceptions.MaxRetryError) as excinfo: webdriver.Remote(command_executor="https://wrong.host.badssl.com/") assert isinstance(excinfo.value.reason, urllib3.exceptions.SSLError) assert "doesn't match" in str(excinfo.value) selenium-selenium-4.23.0/test/selenium/webdriver/remote/remote_firefox_profile_tests.py0000664000175000017500000000231614646203155031547 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium import webdriver @pytest.fixture def driver(options): driver = webdriver.Remote(options=options) yield driver driver.quit() @pytest.fixture def options(): options = webdriver.FirefoxOptions() options.set_preference("browser.startup.homepage", "about:") return options def test_profile_is_used(driver): assert "about:blank" == driver.current_url or "about:" == driver.current_url selenium-selenium-4.23.0/test/selenium/webdriver/__init__.py0000664000175000017500000000142314646203155024032 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.23.0/test/selenium/webdriver/chrome/0000775000175000017500000000000014646203155023176 5ustar carstencarstenselenium-selenium-4.23.0/test/selenium/webdriver/chrome/__init__.py0000664000175000017500000000142314646203155025307 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.23.0/test/selenium/webdriver/chrome/chrome_launcher_tests.py0000664000175000017500000000241314646203155030130 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest @pytest.mark.no_driver_after_test def test_launch_and_close_browser(clean_driver, clean_service): driver = clean_driver(service=clean_service) driver.quit() @pytest.mark.no_driver_after_test def test_we_can_launch_multiple_chrome_instances(clean_driver, clean_service): driver1 = clean_driver(service=clean_service) driver2 = clean_driver(service=clean_service) driver3 = clean_driver(service=clean_service) driver1.quit() driver2.quit() driver3.quit() selenium-selenium-4.23.0/test/selenium/webdriver/chrome/conftest.py0000664000175000017500000000173514646203155025403 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. def pytest_generate_tests(metafunc): if "driver" in metafunc.fixturenames and metafunc.config.option.drivers: metafunc.parametrize("driver", metafunc.config.option.drivers, indirect=True) selenium-selenium-4.23.0/test/selenium/webdriver/chrome/proxy_tests.py0000664000175000017500000000310414646203155026151 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import os import pytest import urllib3 from selenium import webdriver @pytest.mark.no_driver_after_test def test_bad_proxy_doesnt_interfere(clean_driver, clean_service): # these values should be ignored if ignore_local_proxy_environment_variables() is called. os.environ["https_proxy"] = "bad" os.environ["http_proxy"] = "bad" options = webdriver.ChromeOptions() options.ignore_local_proxy_environment_variables() chrome_kwargs = {"options": options, "service": clean_service} driver = clean_driver(**chrome_kwargs) assert hasattr(driver, "command_executor") assert hasattr(driver.command_executor, "_proxy_url") assert isinstance(driver.command_executor._conn, urllib3.PoolManager) os.environ.pop("https_proxy") os.environ.pop("http_proxy") driver.quit() selenium-selenium-4.23.0/test/selenium/webdriver/chrome/chrome_service_tests.py0000664000175000017500000000633514646203155027776 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import os import subprocess import time import pytest from selenium.common.exceptions import WebDriverException from selenium.webdriver.chrome.service import Service @pytest.mark.xfail_chrome(raises=WebDriverException) @pytest.mark.no_driver_after_test def test_uses_chromedriver_logging(clean_driver, driver_executable) -> None: log_file = "chromedriver.log" service_args = ["--append-log"] service = Service( log_output=log_file, service_args=service_args, executable_path=driver_executable, ) driver2 = None try: driver1 = clean_driver(service=service) with open(log_file) as fp: lines = len(fp.readlines()) driver2 = clean_driver(service=service) with open(log_file) as fp: assert len(fp.readlines()) >= 2 * lines finally: driver1.quit() if driver2: driver2.quit() os.remove(log_file) @pytest.mark.no_driver_after_test def test_log_output_as_filename(clean_driver, driver_executable) -> None: log_file = "chromedriver.log" service = Service(log_output=log_file, executable_path=driver_executable) try: assert "--log-path=chromedriver.log" in service.service_args driver = clean_driver(service=service) with open(log_file) as fp: assert "Starting ChromeDriver" in fp.readline() finally: driver.quit() os.remove(log_file) @pytest.mark.no_driver_after_test def test_log_output_as_file(clean_driver, driver_executable) -> None: log_name = "chromedriver.log" log_file = open(log_name, "w", encoding="utf-8") service = Service(log_output=log_file, executable_path=driver_executable) try: driver = clean_driver(service=service) time.sleep(1) with open(log_name) as fp: assert "Starting ChromeDriver" in fp.readline() finally: driver.quit() log_file.close() os.remove(log_name) @pytest.mark.no_driver_after_test def test_log_output_as_stdout(clean_driver, capfd, driver_executable) -> None: service = Service(log_output=subprocess.STDOUT, executable_path=driver_executable) driver = clean_driver(service=service) out, err = capfd.readouterr() assert "Starting ChromeDriver" in out driver.quit() @pytest.mark.no_driver_after_test def test_log_output_null_default(driver, capfd) -> None: out, err = capfd.readouterr() assert "Starting ChromeDriver" not in out driver.quit() selenium-selenium-4.23.0/test/selenium/webdriver/chrome/chrome_network_emulation_tests.py0000664000175000017500000000257214646203155032103 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import WebDriverException @pytest.mark.no_driver_after_test def test_network_conditions_emulation(driver): driver.set_network_conditions(offline=False, latency=56, throughput=789) # additional latency (ms) conditions = driver.get_network_conditions() assert conditions["offline"] is False assert conditions["latency"] == 56 assert conditions["download_throughput"] == 789 assert conditions["upload_throughput"] == 789 driver.delete_network_conditions() with pytest.raises(WebDriverException): driver.get_network_conditions() selenium-selenium-4.23.0/test/selenium/webdriver/ie/0000775000175000017500000000000014646203155022316 5ustar carstencarstenselenium-selenium-4.23.0/test/selenium/webdriver/ie/__init__.py0000664000175000017500000000142314646203155024427 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.23.0/test/selenium/webdriver/ie/ie_launcher_tests.py0000664000175000017500000000322414646203155026371 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from selenium.webdriver import Ie from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.ie.options import Options def test_launch_and_close_browser(): driver = Ie() driver.quit() def test_we_can_launch_multiple_ie_instances(): driver1 = Ie() driver2 = Ie() driver3 = Ie() driver1.quit() driver2.quit() driver3.quit() def test_launch_ie_do_not_affect_default_capabilities(): expected = DesiredCapabilities.INTERNETEXPLORER.copy() driver = Ie() actual = DesiredCapabilities.INTERNETEXPLORER.copy() driver.quit() assert actual == expected def test_launch_ie_with_options(pages): opts = Options() expected = "clicks.html" opts.initial_browser_url = pages.url(expected) driver = Ie(options=opts) actual = driver.current_url driver.quit() assert expected in actual selenium-selenium-4.23.0/test/selenium/webdriver/safari/0000775000175000017500000000000014646203155023166 5ustar carstencarstenselenium-selenium-4.23.0/test/selenium/webdriver/safari/launcher_tests.py0000664000175000017500000000471614646203155026573 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import os import pytest from selenium.common.exceptions import NoSuchDriverException from selenium.webdriver.safari.service import Service def test_launch(driver): assert driver.capabilities["browserName"] == "Safari" def test_launch_with_invalid_executable_path_raises_exception(driver_class): path = "/this/path/should/never/exist" assert not os.path.exists(path) service = Service(executable_path=path) with pytest.raises(NoSuchDriverException): driver_class(service=service) @pytest.mark.skipif( not os.path.exists("/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver"), reason="Preview not installed", ) class TestTechnologyPreview: @pytest.fixture def driver_kwargs(self): path = "/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver" assert os.path.exists( path ), "Safari Technology Preview required! Download it from https://developer.apple.com/safari/technology-preview/" return {"executable_path": path} def test_launch(self, driver): assert driver.capabilities["browserName"] == "safari" def test_launch_safari_with_legacy_flag(mocker, driver_class): import subprocess mocker.patch("subprocess.Popen") try: driver_class(service_args=["--legacy"]) except Exception: pass args, kwargs = subprocess.Popen.call_args assert "--legacy" in args[0] def test_launch_safari_without_legacy_flag(mocker, driver_class): import subprocess mocker.patch("subprocess.Popen") try: driver_class() except Exception: pass args, kwargs = subprocess.Popen.call_args assert "--legacy" not in args[0] selenium-selenium-4.23.0/test/selenium/webdriver/safari/conftest.py0000664000175000017500000000207714646203155025373 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver import Safari @pytest.fixture def driver_class(): return Safari @pytest.fixture def driver_kwargs(): return {} @pytest.fixture def driver(driver_class, driver_kwargs): driver = driver_class(**driver_kwargs) yield driver driver.quit() selenium-selenium-4.23.0/test/selenium/webdriver/common/0000775000175000017500000000000014646203155023211 5ustar carstencarstenselenium-selenium-4.23.0/test/selenium/webdriver/common/element_aria_label_tests.py0000664000175000017500000000217214646203155030573 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.by import By @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_should_return_accessible_name(driver): driver.get("data:text/html,

Level 1 Header

") header1 = driver.find_element(By.CSS_SELECTOR, "h1") assert header1.accessible_name == "Level 1 Header" selenium-selenium-4.23.0/test/selenium/webdriver/common/selenium_manager_tests.py0000664000175000017500000001153614646203155030326 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import json import sys from pathlib import Path from unittest import mock import pytest import selenium from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.selenium_manager import SeleniumManager def test_gets_results(monkeypatch): expected_output = {"driver_path": "/path/to/driver"} lib_path = "selenium.webdriver.common.selenium_manager.SeleniumManager" with mock.patch(lib_path + "._get_binary", return_value="/path/to/sm") as mock_get_binary, mock.patch( lib_path + "._run", return_value=expected_output ) as mock_run: SeleniumManager().binary_paths([]) mock_get_binary.assert_called_once() expected_run_args = ["/path/to/sm", "--language-binding", "python", "--output", "json"] mock_run.assert_called_once_with(expected_run_args) def test_uses_environment_variable(monkeypatch): monkeypatch.setenv("SE_MANAGER_PATH", "/path/to/manager") monkeypatch.setattr(Path, "is_file", lambda _: True) binary = SeleniumManager()._get_binary() assert str(binary) == "/path/to/manager" def test_uses_windows(monkeypatch): monkeypatch.setattr(sys, "platform", "win32") binary = SeleniumManager()._get_binary() project_root = Path(selenium.__file__).parent.parent assert binary == project_root.joinpath("selenium/webdriver/common/windows/selenium-manager.exe") def test_uses_linux(monkeypatch): monkeypatch.setattr(sys, "platform", "linux") binary = SeleniumManager()._get_binary() project_root = Path(selenium.__file__).parent.parent assert binary == project_root.joinpath("selenium/webdriver/common/linux/selenium-manager") def test_uses_mac(monkeypatch): monkeypatch.setattr(sys, "platform", "darwin") binary = SeleniumManager()._get_binary() project_root = Path(selenium.__file__).parent.parent assert binary == project_root.joinpath("selenium/webdriver/common/macos/selenium-manager") def test_errors_if_not_file(monkeypatch): monkeypatch.setattr(Path, "is_file", lambda _: False) with pytest.raises(WebDriverException) as excinfo: SeleniumManager()._get_binary() assert "Unable to obtain working Selenium Manager binary" in str(excinfo.value) def test_errors_if_invalid_os(monkeypatch): monkeypatch.setattr(sys, "platform", "linux") monkeypatch.setattr("platform.machine", lambda: "invalid") with pytest.raises(WebDriverException) as excinfo: SeleniumManager()._get_binary() assert "Unsupported platform/architecture combination" in str(excinfo.value) def test_error_if_invalid_env_path(monkeypatch): monkeypatch.setenv("SE_MANAGER_PATH", "/path/to/manager") with pytest.raises(WebDriverException) as excinfo: SeleniumManager()._get_binary() assert "Unable to obtain working Selenium Manager binary; /path/to/manager" in str(excinfo.value) def test_run_successful(): expected_result = {"driver_path": "/path/to/driver", "browser_path": "/path/to/browser"} run_output = {"result": expected_result, "logs": []} with mock.patch("subprocess.run") as mock_run, mock.patch("json.loads", return_value=run_output): mock_run.return_value = mock.Mock(stdout=json.dumps(run_output).encode("utf-8"), stderr=b"", returncode=0) result = SeleniumManager._run(["arg1", "arg2"]) assert result == expected_result def test_run_exception(): with mock.patch("subprocess.run", side_effect=Exception("Test Error")): with pytest.raises(WebDriverException) as excinfo: SeleniumManager._run(["/path/to/sm", "arg1", "arg2"]) assert "Unsuccessful command executed: /path/to/sm arg1 arg2" in str(excinfo.value) def test_run_non_zero_exit_code(): with mock.patch("subprocess.run") as mock_run, mock.patch("json.loads", return_value={"result": "", "logs": []}): mock_run.return_value = mock.Mock(stdout=b"{}", stderr=b"Error Message", returncode=1) with pytest.raises(WebDriverException) as excinfo: SeleniumManager._run(["/path/to/sm", "arg1"]) assert "Unsuccessful command executed: /path/to/sm arg1; code: 1\n\nError Message" in str(excinfo.value) selenium-selenium-4.23.0/test/selenium/webdriver/common/test_file.txt0000664000175000017500000000003314646203155025724 0ustar carstencarstenlorem ipsum dolor sit amet selenium-selenium-4.23.0/test/selenium/webdriver/common/opacity_tests.py0000664000175000017500000000337714646203155026467 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.by import By @pytest.mark.xfail_ie def test_should_be_able_to_click_on_elements_with_opacity_zero(driver, pages): pages.load("click_jacker.html") element = driver.find_element(By.ID, "clickJacker") assert "0" == element.value_of_css_property("opacity"), ( "Precondition failed: clickJacker should be transparent.\ Value was %s" % element.value_of_css_property("opacity") ) element.click() assert "1" == element.value_of_css_property("opacity") @pytest.mark.xfail_ie def test_should_be_able_to_select_options_from_an_invisible_select(driver, pages): pages.load("formPage.html") select = driver.find_element(By.ID, "invisi_select") options = select.find_elements(By.TAG_NAME, "option") apples = options[0] oranges = options[1] assert apples.is_selected() assert not oranges.is_selected() oranges.click() assert not apples.is_selected() assert oranges.is_selected() selenium-selenium-4.23.0/test/selenium/webdriver/common/implicit_waits_tests.py0000664000175000017500000000514414646203155030032 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.common.by import By def test_should_implicitly_wait_for_asingle_element(driver, pages): pages.load("dynamic.html") add = driver.find_element(By.ID, "adder") driver.implicitly_wait(3) add.click() driver.find_element(By.ID, "box0") # All is well if this doesn't throw. def test_should_still_fail_to_find_an_element_when_implicit_waits_are_enabled(driver, pages): pages.load("dynamic.html") driver.implicitly_wait(0.5) with pytest.raises(NoSuchElementException): driver.find_element(By.ID, "box0") def test_should_return_after_first_attempt_to_find_one_after_disabling_implicit_waits(driver, pages): pages.load("dynamic.html") driver.implicitly_wait(3) driver.implicitly_wait(0) with pytest.raises(NoSuchElementException): driver.find_element(By.ID, "box0") def test_should_implicitly_wait_until_at_least_one_element_is_found_when_searching_for_many(driver, pages): pages.load("dynamic.html") add = driver.find_element(By.ID, "adder") driver.implicitly_wait(2) add.click() add.click() elements = driver.find_elements(By.CLASS_NAME, "redbox") assert len(elements) >= 1 def test_should_still_fail_to_find_an_elemenst_when_implicit_waits_are_enabled(driver, pages): pages.load("dynamic.html") driver.implicitly_wait(0.5) elements = driver.find_elements(By.CLASS_NAME, "redbox") assert 0 == len(elements) def test_should_return_after_first_attempt_to_find_many_after_disabling_implicit_waits(driver, pages): pages.load("dynamic.html") add = driver.find_element(By.ID, "adder") driver.implicitly_wait(1.1) driver.implicitly_wait(0) add.click() elements = driver.find_elements(By.CLASS_NAME, "redbox") assert 0 == len(elements) selenium-selenium-4.23.0/test/selenium/webdriver/common/window_switching_tests.py0000664000175000017500000001647614646203155030411 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import NoSuchWindowException from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By from selenium.webdriver.common.window import WindowTypes from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait @pytest.fixture(autouse=True) def close_windows(driver): main_windows_handle = driver.current_window_handle yield from urllib import request as url_request URLError = url_request.URLError try: window_handles = driver.window_handles except URLError: return for handle in window_handles: if handle != main_windows_handle: driver.switch_to.window(handle) driver.close() driver.switch_to.window(main_windows_handle) def test_should_switch_focus_to_anew_window_when_it_is_opened_and_not_stop_future_operations(driver, pages): pages.load("xhtmlTest.html") current = driver.current_window_handle driver.find_element(By.LINK_TEXT, "Open new window").click() assert driver.title == "XHTML Test Page" handles = driver.window_handles handles.remove(current) driver.switch_to.window(handles[0]) assert driver.title == "We Arrive Here" pages.load("iframes.html") handle = driver.current_window_handle driver.find_element(By.ID, "iframe_page_heading") driver.switch_to.frame(driver.find_element(By.ID, "iframe1")) assert driver.current_window_handle == handle def test_can_switch_to_window_by_name(driver, pages): pages.load("xhtmlTest.html") handles = driver.window_handles driver.find_element(By.LINK_TEXT, "Open new window").click() WebDriverWait(driver, 3).until(EC.new_window_is_opened(handles)) driver.switch_to.window("result") assert driver.title == "We Arrive Here" def test_should_throw_no_such_window_exception(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(NoSuchWindowException): driver.switch_to.window("invalid name") @pytest.mark.xfail_safari def test_should_throw_no_such_window_exception_on_an_attempt_to_get_its_handle(driver, pages): pages.load("xhtmlTest.html") current = driver.current_window_handle handles = driver.window_handles driver.find_element(By.LINK_TEXT, "Open new window").click() WebDriverWait(driver, 3).until(EC.new_window_is_opened(handles)) handles = driver.window_handles handles.remove(current) driver.switch_to.window(handles[0]) driver.close() with pytest.raises(NoSuchWindowException): driver.current_window_handle @pytest.mark.xfail_ie def test_should_throw_no_such_window_exception_on_any_operation_if_awindow_is_closed(driver, pages): pages.load("xhtmlTest.html") current = driver.current_window_handle handles = driver.window_handles driver.find_element(By.LINK_TEXT, "Open new window").click() WebDriverWait(driver, 3).until(EC.new_window_is_opened(handles)) handles = driver.window_handles handles.remove(current) driver.switch_to.window(handles[0]) driver.close() with pytest.raises(NoSuchWindowException): driver.title with pytest.raises(NoSuchWindowException): driver.find_element(By.TAG_NAME, "body") @pytest.mark.xfail_ie @pytest.mark.xfail_safari def test_should_throw_no_such_window_exception_on_any_element_operation_if_awindow_is_closed(driver, pages): pages.load("xhtmlTest.html") current = driver.current_window_handle handles = driver.window_handles driver.find_element(By.LINK_TEXT, "Open new window").click() WebDriverWait(driver, 3).until(EC.new_window_is_opened(handles)) handles = driver.window_handles handles.remove(current) driver.switch_to.window(handles[0]) element = driver.find_element(By.TAG_NAME, "body") driver.close() with pytest.raises(NoSuchWindowException): element.text def test_clicking_on_abutton_that_closes_an_open_window_does_not_cause_the_browser_to_hang(driver, pages): pages.load("xhtmlTest.html") current = driver.current_window_handle handles = driver.window_handles driver.find_element(By.NAME, "windowThree").click() WebDriverWait(driver, 3).until(EC.new_window_is_opened(handles)) handles = driver.window_handles handles.remove(current) driver.switch_to.window(handles[0]) driver.find_element(By.ID, "close").click() driver.switch_to.window(current) driver.find_element(By.ID, "linkId") @pytest.mark.xfail_safari def test_can_call_get_window_handles_after_closing_awindow(driver, pages): pages.load("xhtmlTest.html") current = driver.current_window_handle handles = driver.window_handles driver.find_element(By.NAME, "windowThree").click() WebDriverWait(driver, 3).until(EC.new_window_is_opened(handles)) handles = driver.window_handles handles.remove(current) driver.switch_to.window(handles[0]) driver.find_element(By.ID, "close").click() WebDriverWait(driver, 3).until(EC.number_of_windows_to_be(1)) def test_can_obtain_awindow_handle(driver, pages): pages.load("xhtmlTest.html") currentHandle = driver.current_window_handle assert currentHandle is not None def test_failing_to_switch_to_awindow_leaves_the_current_window_as_is(driver, pages): pages.load("xhtmlTest.html") current = driver.current_window_handle with pytest.raises(NoSuchWindowException): driver.switch_to.window("I will never exist") new_handle = driver.current_window_handle assert current == new_handle @pytest.mark.xfail_safari def test_that_accessing_finding_an_element_after_window_is_closed_and_haventswitched_doesnt_crash(driver, pages): pages.load("xhtmlTest.html") current = driver.current_window_handle handles = driver.window_handles driver.find_element(By.NAME, "windowThree").click() WebDriverWait(driver, 3).until(EC.new_window_is_opened(handles)) handles = driver.window_handles handles.remove(current) driver.switch_to.window(handles[0]) with pytest.raises(WebDriverException): driver.find_element(By.ID, "close").click() all_handles = driver.window_handles assert 1 == len(all_handles) driver.find_element(By.ID, "close") driver.switch_to.window(current) @pytest.mark.xfail_ie def test_should_be_able_to_create_anew_window(driver, pages): original_handle = driver.current_window_handle driver.switch_to.new_window(WindowTypes.TAB) new_handle = driver.current_window_handle driver.close() driver.switch_to.window(original_handle) assert new_handle != original_handle selenium-selenium-4.23.0/test/selenium/webdriver/common/visibility_tests.py0000664000175000017500000001315414646203155027200 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import ElementNotInteractableException from selenium.common.exceptions import ElementNotVisibleException from selenium.webdriver.common.by import By def test_should_allow_the_user_to_tell_if_an_element_is_displayed_or_not(driver, pages): pages.load("javascriptPage.html") assert driver.find_element(by=By.ID, value="displayed").is_displayed() is True assert driver.find_element(by=By.ID, value="none").is_displayed() is False assert driver.find_element(by=By.ID, value="suppressedParagraph").is_displayed() is False assert driver.find_element(by=By.ID, value="hidden").is_displayed() is False def test_visibility_should_take_into_account_parent_visibility(driver, pages): pages.load("javascriptPage.html") childDiv = driver.find_element(by=By.ID, value="hiddenchild") hiddenLink = driver.find_element(by=By.ID, value="hiddenlink") assert childDiv.is_displayed() is False assert hiddenLink.is_displayed() is False def test_should_count_elements_as_visible_if_style_property_has_been_set(driver, pages): pages.load("javascriptPage.html") shown = driver.find_element(by=By.ID, value="visibleSubElement") assert shown.is_displayed() is True @pytest.mark.xfail_safari def test_should_modify_the_visibility_of_an_element_dynamically(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="hideMe") assert element.is_displayed() is True element.click() assert element.is_displayed() is False def test_hidden_input_elements_are_never_visible(driver, pages): pages.load("javascriptPage.html") shown = driver.find_element(by=By.NAME, value="hidden") assert shown.is_displayed() is False def test_should_not_be_able_to_click_on_an_element_that_is_not_displayed(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="unclickable") try: element.click() assert 1 == 0, "should have thrown an exception" except (ElementNotVisibleException, ElementNotInteractableException): pass def test_should_not_be_able_to_toggle_an_element_that_is_not_displayed(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="untogglable") try: element.click() assert 1 == 0, "should have thrown an exception" except (ElementNotVisibleException, ElementNotInteractableException): pass def test_should_not_be_able_to_select_an_element_that_is_not_displayed(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="untogglable") try: element.click() assert 1 == 0, "should have thrown an exception" except (ElementNotVisibleException, ElementNotInteractableException): pass def test_should_not_be_able_to_type_an_element_that_is_not_displayed(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="unclickable") try: element.send_keys("You don't see me") assert 1 == 0, "should have thrown an exception" except (ElementNotVisibleException, ElementNotInteractableException): pass assert element.get_attribute("value") != "You don't see me" def test_should_say_elements_with_negative_transform_are_not_displayed(driver, pages): pages.load("cssTransform.html") elementX = driver.find_element(By.ID, value="parentX") assert elementX.is_displayed() is False elementY = driver.find_element(By.ID, value="parentY") assert elementY.is_displayed() is False def test_should_say_elements_with_parent_with_negative_transform_are_not_displayed(driver, pages): pages.load("cssTransform.html") elementX = driver.find_element(By.ID, value="childX") assert elementX.is_displayed() is False elementY = driver.find_element(By.ID, value="childY") assert elementY.is_displayed() is False def test_should_say_element_with_zero_transform_is_visible(driver, pages): pages.load("cssTransform.html") zero_tranform = driver.find_element(By.ID, "zero-tranform") assert zero_tranform.is_displayed() is True def test_should_say_element_is_visible_when_it_has_negative_transform_but_elementisnt_in_anegative_space(driver, pages): pages.load("cssTransform2.html") zero_tranform = driver.find_element(By.ID, "negative-percentage-transformY") assert zero_tranform.is_displayed() is True def test_should_show_element_not_visible_with_hidden_attribute(driver, pages): pages.load("hidden.html") singleHidden = driver.find_element(By.ID, "singleHidden") assert singleHidden.is_displayed() is False def test_should_show_element_not_visible_when_parent_element_has_hidden_attribute(driver, pages): pages.load("hidden.html") child = driver.find_element(By.ID, "child") assert child.is_displayed() is False selenium-selenium-4.23.0/test/selenium/webdriver/common/__init__.py0000664000175000017500000000142314646203155025322 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.23.0/test/selenium/webdriver/common/executing_javascript_tests.py0000664000175000017500000002422414646203155031232 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By from selenium.webdriver.remote.webelement import WebElement try: str = unicode except NameError: pass def test_should_be_able_to_execute_simple_javascript_and_return_astring(driver, pages): pages.load("xhtmlTest.html") result = driver.execute_script("return document.title") assert isinstance(result, str), "The type of the result is %s" % type(result) assert "XHTML Test Page" == result def test_should_be_able_to_execute_simple_javascript_and_return_an_integer(driver, pages): pages.load("nestedElements.html") result = driver.execute_script("return document.getElementsByName('checky').length") assert isinstance(result, int) assert int(result) > 1 def test_should_be_able_to_execute_simple_javascript_and_return_aweb_element(driver, pages): pages.load("xhtmlTest.html") result = driver.execute_script("return document.getElementById('id1')") assert result is not None assert isinstance(result, WebElement) assert "a" == result.tag_name.lower() def test_should_be_able_to_execute_simple_javascript_and_return_alist_of_web_elements(driver, pages): pages.load("xhtmlTest.html") result = driver.execute_script("return document.querySelectorAll('div.navigation a')") assert result is not None assert isinstance(result, list) assert all(isinstance(item, WebElement) for item in result) assert all("a" == item.tag_name.lower() for item in result) def test_should_be_able_to_execute_simple_javascript_and_return_web_elements_inside_alist(driver, pages): pages.load("xhtmlTest.html") result = driver.execute_script("return [document.body]") assert result is not None assert isinstance(result, list) assert isinstance(result[0], WebElement) def test_should_be_able_to_execute_simple_javascript_and_return_web_elements_inside_anested_list(driver, pages): pages.load("xhtmlTest.html") result = driver.execute_script("return [document.body, [document.getElementById('id1')]]") assert result is not None assert isinstance(result, list) assert isinstance(result[0], WebElement) assert isinstance(result[1][0], WebElement) def test_should_be_able_to_execute_simple_javascript_and_return_web_elements_inside_adict(driver, pages): pages.load("xhtmlTest.html") result = driver.execute_script("return {el1: document.body}") assert result is not None assert isinstance(result, dict) assert isinstance(result.get("el1"), WebElement) def test_should_be_able_to_execute_simple_javascript_and_return_web_elements_inside_anested_dict(driver, pages): pages.load("xhtmlTest.html") result = driver.execute_script("return {el1: document.body, " "nested: {el2: document.getElementById('id1')}}") assert result is not None assert isinstance(result, dict) assert isinstance(result.get("el1"), WebElement) assert isinstance(result.get("nested").get("el2"), WebElement) def test_should_be_able_to_execute_simple_javascript_and_return_web_elements_inside_alist_inside_adict(driver, pages): pages.load("xhtmlTest.html") result = driver.execute_script("return {el1: [document.body]}") assert result is not None assert isinstance(result, dict) assert isinstance(result.get("el1"), list) assert isinstance(result.get("el1")[0], WebElement) def test_should_be_able_to_execute_simple_javascript_and_return_aboolean(driver, pages): pages.load("xhtmlTest.html") result = driver.execute_script("return true") assert result is not None assert isinstance(result, bool) assert bool(result) def test_should_be_able_to_execute_simple_javascript_and_astrings_array(driver, pages): pages.load("javascriptPage.html") expectedResult = [] expectedResult.append("zero") expectedResult.append("one") expectedResult.append("two") result = driver.execute_script("return ['zero', 'one', 'two']") assert expectedResult == result def test_should_be_able_to_execute_simple_javascript_and_return_an_array(driver, pages): pages.load("javascriptPage.html") expectedResult = [] expectedResult.append("zero") subList = [] subList.append(True) subList.append(False) expectedResult.append(subList) result = driver.execute_script("return ['zero', [true, false]]") assert result is not None assert isinstance(result, list) assert expectedResult == result def test_passing_and_returning_an_int_should_return_awhole_number(driver, pages): pages.load("javascriptPage.html") expectedResult = 1 result = driver.execute_script("return arguments[0]", expectedResult) assert isinstance(result, int) assert expectedResult == result def test_passing_and_returning_adouble_should_return_adecimal(driver, pages): pages.load("javascriptPage.html") expectedResult = 1.2 result = driver.execute_script("return arguments[0]", expectedResult) assert isinstance(result, float) assert expectedResult == result def test_should_throw_an_exception_when_the_javascript_is_bad(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(WebDriverException): driver.execute_script("return squiggle()") def test_should_be_able_to_call_functions_defined_on_the_page(driver, pages): pages.load("javascriptPage.html") driver.execute_script("displayMessage('I like cheese')") text = driver.find_element(By.ID, "result").text assert "I like cheese" == text.strip() def test_should_be_able_to_pass_astring_an_as_argument(driver, pages): pages.load("javascriptPage.html") value = driver.execute_script("return arguments[0] == 'fish' ? 'fish' : 'not fish'", "fish") assert "fish" == value def test_should_be_able_to_pass_aboolean_an_as_argument(driver, pages): pages.load("javascriptPage.html") value = bool(driver.execute_script("return arguments[0] == true", True)) assert value def test_should_be_able_to_pass_anumber_an_as_argument(driver, pages): pages.load("javascriptPage.html") value = bool(driver.execute_script("return arguments[0] == 1 ? true : false", 1)) assert value def test_should_be_able_to_pass_aweb_element_as_argument(driver, pages): pages.load("javascriptPage.html") button = driver.find_element(By.ID, "plainButton") value = driver.execute_script( "arguments[0]['flibble'] = arguments[0].getAttribute('id'); return arguments[0]['flibble']", button ) assert "plainButton" == value def test_should_be_able_to_pass_an_array_as_argument(driver, pages): pages.load("javascriptPage.html") array = ["zero", 1, True, 3.14159] length = int(driver.execute_script("return arguments[0].length", array)) assert len(array) == length def test_should_be_able_to_pass_acollection_as_argument(driver, pages): pages.load("javascriptPage.html") collection = [] collection.append("Cheddar") collection.append("Brie") collection.append(7) length = int(driver.execute_script("return arguments[0].length", collection)) assert len(collection) == length collection = [] collection.append("Gouda") collection.append("Stilton") collection.append("Stilton") collection.append(True) length = int(driver.execute_script("return arguments[0].length", collection)) assert len(collection) == length def test_should_throw_an_exception_if_an_argument_is_not_valid(driver, pages): pages.load("javascriptPage.html") with pytest.raises(Exception): driver.execute_script("return arguments[0]", driver) def test_should_be_able_to_pass_in_more_than_one_argument(driver, pages): pages.load("javascriptPage.html") result = driver.execute_script("return arguments[0] + arguments[1]", "one", "two") assert "onetwo" == result def test_javascript_string_handling_should_work_as_expected(driver, pages): pages.load("javascriptPage.html") value = driver.execute_script("return ''") assert "" == value value = driver.execute_script("return undefined") assert value is None value = driver.execute_script("return ' '") assert " " == value def test_should_be_able_to_create_apersistent_value(driver, pages): pages.load("formPage.html") driver.execute_script("document.alerts = []") driver.execute_script("document.alerts.push('hello world')") text = driver.execute_script("return document.alerts.shift()") assert "hello world" == text def test_can_pass_adictionary_as_aparameter(driver, pages): pages.load("simpleTest.html") nums = [1, 2] args = {"bar": "test", "foo": nums} res = driver.execute_script("return arguments[0]['foo'][1]", args) assert 2 == res def test_can_pass_anone(driver, pages): pages.load("simpleTest.html") res = driver.execute_script("return arguments[0] === null", None) assert res def test_can_return_a_const(driver, pages): pages.load("simpleTest.html") res = driver.execute_script("const cheese='cheese'; return cheese") assert res == "cheese" def test_can_return_a_const_in_a_page(driver, pages): pages.load("const_js.html") res = driver.execute_script("return makeMeA('sandwich');") assert res == "cheese sandwich" @pytest.mark.xfail_remote @pytest.mark.xfail_firefox def test_can_return_global_const(driver, pages): pages.load("const_js.html") # cheese is a variable with "cheese" in it res = driver.execute_script("return cheese") assert res == "cheese" selenium-selenium-4.23.0/test/selenium/webdriver/common/stale_reference_tests.py0000664000175000017500000000351714646203155030141 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import StaleElementReferenceException from selenium.webdriver.common.by import By def test_old_page(driver, pages): pages.load("simpleTest.html") elem = driver.find_element(by=By.ID, value="links") pages.load("xhtmlTest.html") msg = r"\/errors#stale-element-reference-exception" with pytest.raises(StaleElementReferenceException, match=msg): elem.click() @pytest.mark.xfail_safari def test_should_not_crash_when_calling_get_size_on_an_obsolete_element(driver, pages): pages.load("simpleTest.html") elem = driver.find_element(by=By.ID, value="links") pages.load("xhtmlTest.html") with pytest.raises(StaleElementReferenceException): elem.size @pytest.mark.xfail_safari def test_should_not_crash_when_querying_the_attribute_of_astale_element(driver, pages): pages.load("xhtmlTest.html") heading = driver.find_element(by=By.XPATH, value="//h1") pages.load("simpleTest.html") with pytest.raises(StaleElementReferenceException): heading.get_attribute("class") selenium-selenium-4.23.0/test/selenium/webdriver/common/devtools_tests.py0000664000175000017500000000302714646203155026646 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.support.ui import WebDriverWait @pytest.mark.xfail_safari def test_check_console_messages(driver, pages): devtools, connection = driver.start_devtools() console_api_calls = [] connection.execute(devtools.runtime.enable()) connection.on(devtools.runtime.ConsoleAPICalled, console_api_calls.append) driver.execute_script("console.log('I love cheese')") driver.execute_script("console.error('I love bread')") WebDriverWait(driver, 5).until(lambda _: len(console_api_calls) == 2) assert console_api_calls[0].type_ == "log" assert console_api_calls[0].args[0].value == "I love cheese" assert console_api_calls[1].type_ == "error" assert console_api_calls[1].args[0].value == "I love bread" selenium-selenium-4.23.0/test/selenium/webdriver/common/cookie_tests.py0000664000175000017500000001177514646203155026271 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import calendar import random import time import pytest @pytest.fixture def cookie(webserver): cookie = {"name": "foo", "value": "bar", "domain": webserver.host, "path": "/", "secure": False} return cookie @pytest.fixture def same_site_cookie_strict(webserver): same_site_cookie_strict = { "name": "foo", "value": "bar", "path": "/", "domain": webserver.host, "sameSite": "Strict", "secure": False, } return same_site_cookie_strict @pytest.fixture def same_site_cookie_lax(webserver): same_site_cookie_lax = { "name": "foo", "value": "bar", "path": "/", "domain": webserver.host, "sameSite": "Lax", "secure": False, } return same_site_cookie_lax @pytest.fixture def same_site_cookie_none(webserver): same_site_cookie_none = { "name": "foo", "value": "bar", "path": "/", "domain": webserver.host, "sameSite": "None", "secure": True, } return same_site_cookie_none @pytest.fixture(autouse=True) def pages(request, driver, pages): pages.load("simpleTest.html") yield pages driver.delete_all_cookies() def test_add_cookie(cookie, driver): driver.add_cookie(cookie) returned = driver.execute_script("return document.cookie") assert cookie["name"] in returned @pytest.mark.xfail_firefox(reason="sameSite cookie attribute not implemented") @pytest.mark.xfail_remote(reason="sameSite cookie attribute not implemented") @pytest.mark.xfail_safari def test_add_cookie_same_site_strict(same_site_cookie_strict, driver): driver.add_cookie(same_site_cookie_strict) returned = driver.get_cookie("foo") assert "sameSite" in returned and returned["sameSite"] == "Strict" @pytest.mark.xfail_firefox(reason="sameSite cookie attribute not implemented") @pytest.mark.xfail_remote(reason="sameSite cookie attribute not implemented") @pytest.mark.xfail_safari def test_add_cookie_same_site_lax(same_site_cookie_lax, driver): driver.add_cookie(same_site_cookie_lax) returned = driver.get_cookie("foo") assert "sameSite" in returned and returned["sameSite"] == "Lax" @pytest.mark.xfail_firefox(reason="sameSite cookie attribute not implemented") @pytest.mark.xfail_remote(reason="sameSite cookie attribute not implemented") @pytest.mark.xfail_safari def test_add_cookie_same_site_none(same_site_cookie_none, driver): driver.add_cookie(same_site_cookie_none) # Note that insecure sites (http:) can't set cookies with the Secure directive. # driver.get_cookie would return None @pytest.mark.xfail_ie @pytest.mark.xfail_safari def test_adding_acookie_that_expired_in_the_past(cookie, driver): expired = cookie.copy() expired["expiry"] = calendar.timegm(time.gmtime()) - 1 driver.add_cookie(expired) assert 0 == len(driver.get_cookies()) def test_delete_all_cookie(cookie, driver): driver.add_cookie(cookie) driver.delete_all_cookies() assert not driver.get_cookies() def test_delete_cookie(cookie, driver): driver.add_cookie(cookie) driver.delete_cookie("foo") assert not driver.get_cookies() def test_should_get_cookie_by_name(driver): key = f"key_{int(random.random() * 10000000)}" driver.execute_script("document.cookie = arguments[0] + '=set';", key) cookie = driver.get_cookie(key) assert "set" == cookie["value"] def test_should_return_none_when_cookie_does_not_exist(driver): key = f"key_{int(random.random() * 10000000)}" cookie = driver.get_cookie(key) assert cookie is None def test_get_all_cookies(cookie, driver, pages, webserver): cookies = driver.get_cookies() count = len(cookies) for i in range(2): cookie["name"] = f"key_{int(random.random() * 10000000)}" driver.add_cookie(cookie) pages.load("simpleTest.html") assert count + 2 == len(driver.get_cookies()) def test_should_not_delete_cookies_with_asimilar_name(cookie, driver, webserver): cookie2 = cookie.copy() cookie2["name"] = "{}x".format(cookie["name"]) driver.add_cookie(cookie) driver.add_cookie(cookie2) driver.delete_cookie(cookie["name"]) cookies = driver.get_cookies() assert cookie["name"] != cookies[0]["name"] assert cookie2["name"] == cookies[0]["name"] selenium-selenium-4.23.0/test/selenium/webdriver/common/rendered_webelement_tests.py0000664000175000017500000000470114646203155031006 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By from selenium.webdriver.support.color import Color def test_should_pick_up_style_of_an_element(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="green-parent") backgroundColour = Color.from_string(element.value_of_css_property("background-color")) assert Color.from_string("rgba(0, 128, 0, 1)") == backgroundColour element = driver.find_element(by=By.ID, value="red-item") backgroundColour = Color.from_string(element.value_of_css_property("background-color")) assert Color.from_string("rgba(255, 0, 0, 1)") == backgroundColour def test_should_allow_inherited_styles_to_be_used(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="green-item") backgroundColour = Color.from_string(element.value_of_css_property("background-color")) assert backgroundColour == Color.from_string("transparent") def test_should_correctly_identify_that_an_element_has_width(driver, pages): pages.load("xhtmlTest.html") shrinko = driver.find_element(by=By.ID, value="linkId") size = shrinko.size assert size["width"] > 0 assert size["height"] > 0 @pytest.mark.xfail_safari(reason="Get Element Rect command not implemented", raises=WebDriverException) def test_should_be_able_to_determine_the_rect_of_an_element(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.ID, "username") rect = element.rect assert rect["x"] > 0 assert rect["y"] > 0 assert rect["width"] > 0 assert rect["height"] > 0 selenium-selenium-4.23.0/test/selenium/webdriver/common/interactions_with_device_tests.py0000664000175000017500000003306314646203155032066 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """Tests for advanced user interactions.""" import pytest from selenium.common.exceptions import MoveTargetOutOfBoundsException from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.actions import interaction from selenium.webdriver.common.actions.key_input import KeyInput from selenium.webdriver.common.actions.pointer_input import PointerInput from selenium.webdriver.common.actions.wheel_input import ScrollOrigin from selenium.webdriver.common.actions.wheel_input import WheelInput from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.ui import WebDriverWait def _is_element_available(driver, id): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" try: driver.find_element(By.ID, id) return True except Exception: return False @pytest.mark.xfail_safari @pytest.mark.xfail_chrome def test_drag_and_drop_with_pointer(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" element_available_timeout = 15 wait = WebDriverWait(driver, element_available_timeout) pages.load("droppableItems.html") wait.until(lambda dr: _is_element_available(driver, "draggable")) if not _is_element_available(driver, "draggable"): raise AssertionError("Could not find draggable element after 15 seconds.") toDrag = driver.find_element(By.ID, "draggable") dropInto = driver.find_element(By.ID, "droppable") mouse = PointerInput(interaction.POINTER_MOUSE, "test mouse") holdDrag = ActionChains(driver, devices=[mouse]).click_and_hold(toDrag) move = ActionChains(driver, devices=[mouse]).move_to_element(dropInto) drop = ActionChains(driver, devices=[mouse]).release(dropInto) holdDrag.perform() move.perform() drop.perform() dropInto = driver.find_element(By.ID, "droppable") text = dropInto.find_element(By.TAG_NAME, "p").text assert "Dropped!" == text @pytest.mark.xfail_safari def test_double_click_with_pointer(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" pages.load("javascriptPage.html") toDoubleClick = driver.find_element(By.ID, "doubleClickField") mouse = PointerInput(interaction.POINTER_MOUSE, "test mouse") dblClick = ActionChains(driver, devices=[mouse]).double_click(toDoubleClick) dblClick.perform() assert "DoubleClicked" == toDoubleClick.get_attribute("value") def test_context_click_with_pointer(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" pages.load("javascriptPage.html") toContextClick = driver.find_element(By.ID, "doubleClickField") mouse = PointerInput(interaction.POINTER_MOUSE, "test mouse") contextClick = ActionChains(driver, devices=[mouse]).context_click(toContextClick) contextClick.perform() assert "ContextClicked" == toContextClick.get_attribute("value") def test_move_and_click_with_pointer(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" pages.load("javascriptPage.html") toClick = driver.find_element(By.ID, "clickField") mouse = PointerInput(interaction.POINTER_MOUSE, "test mouse") click = ActionChains(driver, devices=[mouse]).move_to_element(toClick).click() click.perform() assert "Clicked" == toClick.get_attribute("value") def test_cannot_move_to_anull_locator_with_pointer(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" pages.load("javascriptPage.html") mouse = PointerInput(interaction.POINTER_MOUSE, "test mouse") with pytest.raises(AttributeError): move = ActionChains(driver, devices=[mouse]).move_to_element(None) move.perform() @pytest.mark.xfail_safari def test_clicking_on_form_elements_with_pointer(driver, pages): """Copied from org.openqa.selenium.interactions.CombinedInputActionsTest.""" pages.load("formSelectionPage.html") options = driver.find_elements(By.TAG_NAME, "option") mouse = PointerInput(interaction.POINTER_MOUSE, "test mouse") selectThreeOptions = ( ActionChains(driver, devices=[mouse]) .click(options[1]) .key_down(Keys.SHIFT) .click(options[3]) .key_up(Keys.SHIFT) ) selectThreeOptions.perform() showButton = driver.find_element(By.NAME, "showselected") showButton.click() resultElement = driver.find_element(By.ID, "result") assert "roquefort parmigiano cheddar" == resultElement.text @pytest.mark.xfail_firefox @pytest.mark.xfail_safari def test_selecting_multiple_items_with_devices(driver, pages): """Copied from org.openqa.selenium.interactions.CombinedInputActionsTest.""" pages.load("selectableItems.html") reportingElement = driver.find_element(By.ID, "infodiv") assert "no info" == reportingElement.text mouse = PointerInput(interaction.POINTER_MOUSE, "test mouse") key_board = KeyInput("test keyboard") listItems = driver.find_elements(By.TAG_NAME, "li") selectThreeItems = ( ActionChains(driver, devices=[mouse, key_board]) .key_down(Keys.CONTROL) .click(listItems[1]) .click(listItems[3]) .click(listItems[5]) .key_up(Keys.CONTROL) ) selectThreeItems.perform() assert "#item2 #item4 #item6" == reportingElement.text # Now click on another element, make sure that's the only one selected. actionsBuilder = ActionChains(driver) actionsBuilder.click(listItems[6]).perform() assert "#item7" == reportingElement.text @pytest.mark.xfail_safari def test_sending_keys_to_active_element_with_modifier_with_keyboard(driver, pages): pages.load("formPage.html") e = driver.find_element(By.ID, "working") e.click() key_board = KeyInput("test keyboard") ActionChains(driver, devices=[key_board]).key_down(Keys.SHIFT).send_keys("abc").key_up(Keys.SHIFT).perform() assert "ABC" == e.get_attribute("value") def test_sending_keys_to_element_with_keyboard(driver, pages): pages.load("formPage.html") e = driver.find_element(By.ID, "working") key_board = KeyInput("test keyboard") ActionChains(driver, devices=[key_board]).send_keys_to_element(e, "abc").perform() assert "abc" == e.get_attribute("value") def test_can_send_keys_between_clicks_with_keyboard(driver, pages): """ For W3C, ensures that the correct number of pauses are given to the other input device. """ pages.load("javascriptPage.html") keyup = driver.find_element(By.ID, "keyUp") keydown = driver.find_element(By.ID, "keyDown") key_board = KeyInput("test keyboard") ActionChains(driver, devices=[key_board]).click(keyup).send_keys("foobar").click(keydown).perform() assert "foobar" == keyup.get_attribute("value") def test_can_reset_interactions_with_devices(driver): mouse = PointerInput(interaction.POINTER_MOUSE, "test mouse") key_board = KeyInput("test keyboard") actions = ActionChains(driver, devices=[mouse, key_board]) actions.click() actions.key_down("A") assert all(len(device.actions) >= 0 for device in actions.w3c_actions.devices if device.type != interaction.WHEEL) actions.reset_actions() assert all(len(device.actions) == 0 for device in actions.w3c_actions.devices) def test_can_pause_with_pointer(driver, pages): from time import time pages.load("javascriptPage.html") pause_time = 2 toClick = driver.find_element(By.ID, "clickField") toDoubleClick = driver.find_element(By.ID, "doubleClickField") mouse = PointerInput(interaction.POINTER_MOUSE, "test mouse") pause = ActionChains(driver, devices=[mouse]).click(toClick).pause(pause_time).click(toDoubleClick) start = time() pause.perform() end = time() assert pause_time < end - start assert "Clicked" == toClick.get_attribute("value") assert "Clicked" == toDoubleClick.get_attribute("value") @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_scroll_to_element_with_wheel(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html") iframe = driver.find_element(By.TAG_NAME, "iframe") assert not _in_viewport(driver, iframe) wheel = WheelInput("test wheel") ActionChains(driver, devices=[wheel]).scroll_to_element(iframe).perform() assert _in_viewport(driver, iframe) @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_scroll_from_element_by_amount_with_wheel(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html") iframe = driver.find_element(By.TAG_NAME, "iframe") scroll_origin = ScrollOrigin.from_element(iframe) wheel = WheelInput("test wheel") ActionChains(driver, devices=[wheel]).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform() driver.switch_to.frame(iframe) checkbox = driver.find_element(By.NAME, "scroll_checkbox") assert _in_viewport(driver, checkbox) @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_scroll_from_element_with_offset_by_amount_with_wheel(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html") footer = driver.find_element(By.TAG_NAME, "footer") scroll_origin = ScrollOrigin.from_element(footer, 0, -50) wheel = WheelInput("test wheel") ActionChains(driver, devices=[wheel]).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform() iframe = driver.find_element(By.TAG_NAME, "iframe") driver.switch_to.frame(iframe) checkbox = driver.find_element(By.NAME, "scroll_checkbox") assert _in_viewport(driver, checkbox) @pytest.mark.xfail_firefox def test_errors_when_element_offset_not_in_viewport_with_wheel(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html") footer = driver.find_element(By.TAG_NAME, "footer") scroll_origin = ScrollOrigin.from_element(footer, 0, 50) wheel = WheelInput("test wheel") with pytest.raises(MoveTargetOutOfBoundsException): ActionChains(driver, devices=[wheel]).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform() @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_scroll_from_viewport_by_amount_with_wheel(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html") footer = driver.find_element(By.TAG_NAME, "footer") delta_y = footer.rect["y"] wheel = WheelInput("test wheel") ActionChains(driver, devices=[wheel]).scroll_by_amount(0, delta_y).pause(0.2).perform() assert _in_viewport(driver, footer) @pytest.mark.xfail_firefox def test_can_scroll_from_viewport_with_offset_by_amount_with_wheel(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame.html") scroll_origin = ScrollOrigin.from_viewport(10, 10) wheel = WheelInput("test wheel") ActionChains(driver, devices=[wheel]).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform() iframe = driver.find_element(By.TAG_NAME, "iframe") driver.switch_to.frame(iframe) checkbox = driver.find_element(By.NAME, "scroll_checkbox") assert _in_viewport(driver, checkbox) @pytest.mark.xfail_firefox def test_errors_when_origin_offset_not_in_viewport_with_wheel(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame.html") scroll_origin = ScrollOrigin.from_viewport(-10, -10) wheel = WheelInput("test wheel") with pytest.raises(MoveTargetOutOfBoundsException): ActionChains(driver, devices=[wheel]).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform() def _get_events(driver): """Return list of key events recorded in the test_keys_page fixture.""" events = driver.execute_script("return allEvents.events;") or [] # `key` values in `allEvents` may be escaped (see `escapeSurrogateHalf` in # test_keys_wdspec.html), so this converts them back into unicode literals. for e in events: # example: turn "U+d83d" (6 chars) into u"\ud83d" (1 char) if "key" in e and e["key"].startswith("U+"): key = e["key"] hex_suffix = key[key.index("+") + 1 :] e["key"] = chr(int(hex_suffix, 16)) # WebKit sets code as 'Unidentified' for unidentified key codes, but # tests expect ''. if "code" in e and e["code"] == "Unidentified": e["code"] = "" return events def _in_viewport(driver, element): script = ( "for(var e=arguments[0],f=e.offsetTop,t=e.offsetLeft,o=e.offsetWidth,n=e.offsetHeight;\n" "e.offsetParent;)f+=(e=e.offsetParent).offsetTop,t+=e.offsetLeft;\n" "return f\n" "window.pageYOffset&&t+o>window.pageXOffset" ) return driver.execute_script(script, element) selenium-selenium-4.23.0/test/selenium/webdriver/common/click_scrolling_tests.py0000664000175000017500000001573514646203155030161 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import MoveTargetOutOfBoundsException from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait def test_clicking_on_anchor_scrolls_page(driver, pages): scrollScript = """var pageY; if (typeof(window.pageYOffset) == 'number') { pageY = window.pageYOffset; } else { pageY = document.documentElement.scrollTop; } return pageY;""" pages.load("macbeth.html") driver.find_element(By.PARTIAL_LINK_TEXT, "last speech").click() yOffset = driver.execute_script(scrollScript) # Focusing on to click, but not actually following, # the link will scroll it in to view, which is a few pixels further than 0 assert yOffset > 300 def test_should_scroll_to_click_on_an_element_hidden_by_overflow(driver, pages): pages.load("click_out_of_bounds_overflow.html") link = driver.find_element(By.ID, "link") try: link.click() except MoveTargetOutOfBoundsException as e: AssertionError("Should not be out of bounds: %s" % e.msg) def test_should_be_able_to_click_on_an_element_hidden_by_overflow(driver, pages): pages.load("scroll.html") link = driver.find_element(By.ID, "line8") # This used to throw a MoveTargetOutOfBoundsException - we don't expect it to link.click() assert "line8" == driver.find_element(By.ID, "clicked").text @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_should_be_able_to_click_on_an_element_hidden_by_double_overflow(driver, pages): pages.load("scrolling_tests/page_with_double_overflow_auto.html") driver.find_element(By.ID, "link").click() WebDriverWait(driver, 3).until(EC.title_is("Clicked Successfully!")) def test_should_be_able_to_click_on_an_element_hidden_by_yoverflow(driver, pages): pages.load("scrolling_tests/page_with_y_overflow_auto.html") driver.find_element(By.ID, "link").click() WebDriverWait(driver, 3).until(EC.title_is("Clicked Successfully!")) def test_should_not_scroll_overflow_elements_which_are_visible(driver, pages): pages.load("scroll2.html") list = driver.find_element(By.TAG_NAME, "ul") item = list.find_element(By.ID, "desired") item.click() yOffset = driver.execute_script("return arguments[0].scrollTop", list) assert 0 == yOffset, "Should not have scrolled" @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_should_not_scroll_if_already_scrolled_and_element_is_in_view(driver, pages): pages.load("scroll3.html") driver.find_element(By.ID, "button2").click() scrollTop = get_scroll_top(driver) driver.find_element(By.ID, "button1").click() assert scrollTop == get_scroll_top(driver) def test_should_be_able_to_click_radio_button_scrolled_into_view(driver, pages): pages.load("scroll4.html") driver.find_element(By.ID, "radio").click() # If we don't throw, we're good @pytest.mark.xfail_safari def test_should_scroll_overflow_elements_if_click_point_is_out_of_view_but_element_is_in_view(driver, pages): pages.load("scroll5.html") driver.find_element(By.ID, "inner").click() assert "clicked" == driver.find_element(By.ID, "clicked").text @pytest.mark.xfail_firefox(reason="https://github.com/w3c/webdriver/issues/408") @pytest.mark.xfail_remote(reason="https://github.com/w3c/webdriver/issues/408") @pytest.mark.xfail_safari def test_should_be_able_to_click_element_in_aframe_that_is_out_of_view(driver, pages): pages.load("scrolling_tests/page_with_frame_out_of_view.html") driver.switch_to.frame(driver.find_element(By.NAME, "frame")) element = driver.find_element(By.NAME, "checkbox") element.click() assert element.is_selected() def test_should_be_able_to_click_element_that_is_out_of_view_in_aframe(driver, pages): pages.load("scrolling_tests/page_with_scrolling_frame.html") driver.switch_to.frame(driver.find_element(By.NAME, "scrolling_frame")) element = driver.find_element(By.NAME, "scroll_checkbox") element.click() assert element.is_selected() def test_should_not_be_able_to_click_element_that_is_out_of_view_in_anon_scrollable_frame(driver, pages): pages.load("scrolling_tests/page_with_non_scrolling_frame.html") driver.switch_to.frame("scrolling_frame") element = driver.find_element(By.NAME, "scroll_checkbox") element.click() # TODO we should assert that the click was unsuccessful @pytest.mark.xfail_safari def test_should_be_able_to_click_element_that_is_out_of_view_in_aframe_that_is_out_of_view(driver, pages): pages.load("scrolling_tests/page_with_scrolling_frame_out_of_view.html") driver.switch_to.frame(driver.find_element(By.NAME, "scrolling_frame")) element = driver.find_element(By.NAME, "scroll_checkbox") element.click() assert element.is_selected() @pytest.mark.xfail_firefox @pytest.mark.xfail_chrome @pytest.mark.xfail_remote def test_should_be_able_to_click_element_that_is_out_of_view_in_anested_frame(driver, pages): pages.load("scrolling_tests/page_with_nested_scrolling_frames.html") driver.switch_to.frame(driver.find_element(By.NAME, "scrolling_frame")) driver.switch_to.frame(driver.find_element(By.NAME, "nested_scrolling_frame")) element = driver.find_element(By.NAME, "scroll_checkbox") element.click() assert element.is_selected() @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_chrome @pytest.mark.xfail_remote def test_should_be_able_to_click_element_that_is_out_of_view_in_anested_frame_that_is_out_of_view(driver, pages): pages.load("scrolling_tests/page_with_nested_scrolling_frames_out_of_view.html") driver.switch_to.frame(driver.find_element(By.NAME, "scrolling_frame")) driver.switch_to.frame(driver.find_element(By.NAME, "nested_scrolling_frame")) element = driver.find_element(By.NAME, "scroll_checkbox") element.click() assert element.is_selected() def test_should_not_scroll_when_getting_element_size(driver, pages): pages.load("scroll3.html") scrollTop = get_scroll_top(driver) driver.find_element(By.ID, "button1").size assert scrollTop == get_scroll_top(driver) def get_scroll_top(driver): return driver.execute_script("return document.body.scrollTop") selenium-selenium-4.23.0/test/selenium/webdriver/common/web_components_tests.py0000664000175000017500000000552714646203155030040 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import NoSuchShadowRootException from selenium.webdriver.common.by import By from selenium.webdriver.remote.shadowroot import ShadowRoot from selenium.webdriver.remote.webelement import WebElement @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_can_get_the_shadow_root_of_an_element(driver, pages): pages.load("webComponents.html") shadow_root = driver.find_element(By.CSS_SELECTOR, "custom-checkbox-element").shadow_root assert isinstance(shadow_root, ShadowRoot) @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_no_such_shadow_root_thrown_when_no_shadow_root(driver, pages): with pytest.raises(NoSuchShadowRootException): pages.load("simpleTest.html") driver.find_element(By.CSS_SELECTOR, "div").shadow_root @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_returns_shadow_root_via_execute_script(driver, pages): pages.load("webComponents.html") custom_element = driver.find_element(By.CSS_SELECTOR, "custom-checkbox-element") shadow_root = custom_element.shadow_root execute_shadow_root = driver.execute_script("return arguments[0].shadowRoot", custom_element) assert shadow_root == execute_shadow_root @pytest.mark.xfail_safari @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_find_element_in_a_shadowroot(driver, pages): pages.load("webComponents.html") custom_element = driver.find_element(By.CSS_SELECTOR, "custom-checkbox-element") shadow_root = custom_element.shadow_root element = shadow_root.find_element(By.CSS_SELECTOR, "input") assert isinstance(element, WebElement) @pytest.mark.xfail_safari @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_find_elements_in_a_shadow_root(driver, pages): pages.load("webComponents.html") custom_element = driver.find_element(By.CSS_SELECTOR, "custom-checkbox-element") shadow_root = custom_element.shadow_root elements = shadow_root.find_elements(By.CSS_SELECTOR, "input") assert len(elements) == 1 assert isinstance(elements[0], WebElement) selenium-selenium-4.23.0/test/selenium/webdriver/common/repr_tests.py0000664000175000017500000000304214646203155025754 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait def test_should_implement_repr_for_web_driver(driver): driver_repr = repr(driver) assert type(driver).__name__ in driver_repr assert driver.session_id in driver_repr def test_should_implement_repr_for_web_element(driver, pages): pages.load("simpleTest.html") elem = driver.find_element(By.ID, "validImgTag") elem_repr = repr(elem) assert type(elem).__name__ in elem_repr assert driver.session_id in elem_repr assert elem._id in elem_repr def test_should_implement_repr_for_wait(driver): wait = WebDriverWait(driver, 30) wait_repr = repr(wait) assert type(wait).__name__ in wait_repr assert driver.session_id in wait_repr selenium-selenium-4.23.0/test/selenium/webdriver/common/page_load_timeout_tests.py0000664000175000017500000000265214646203155030473 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import TimeoutException from selenium.webdriver.common.by import By @pytest.fixture(autouse=True) def reset_timeouts(driver): yield driver.set_page_load_timeout(300) def test_should_timeout_on_page_load_taking_too_long(driver, pages): driver.set_page_load_timeout(0.01) with pytest.raises(TimeoutException): pages.load("simpleTest.html") @pytest.mark.xfail_safari def test_click_should_timeout(driver, pages): pages.load("simpleTest.html") driver.set_page_load_timeout(0.01) with pytest.raises(TimeoutException): driver.find_element(By.ID, "multilinelink").click() selenium-selenium-4.23.0/test/selenium/webdriver/common/select_element_handling_tests.py0000664000175000017500000000674514646203155031655 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from selenium.webdriver.common.by import By def test_should_be_possible_to_deselect_asingle_option_from_aselect_which_allows_multiple_choice(driver, pages): pages.load("formPage.html") multiSelect = driver.find_element(By.ID, "multi") options = multiSelect.find_elements(By.TAG_NAME, "option") option = options[0] assert option.is_selected() is True option.click() assert option.is_selected() is False option.click() assert option.is_selected() is True option = options[2] assert option.is_selected() is True def test_should_be_able_to_change_the_selected_option_in_aselec(driver, pages): pages.load("formPage.html") selectBox = driver.find_element(By.XPATH, "//select[@name='selectomatic']") options = selectBox.find_elements(By.TAG_NAME, "option") one = options[0] two = options[1] assert one.is_selected() is True assert two.is_selected() is False two.click() assert one.is_selected() is False assert two.is_selected() is True def test_should_be_able_to_select_more_than_one_option_from_aselect_which_allows_multiple_choice(driver, pages): pages.load("formPage.html") multiSelect = driver.find_element(By.ID, "multi") options = multiSelect.find_elements(By.TAG_NAME, "option") for option in options: if not option.is_selected(): option.click() for i in range(len(options)): option = options[i] assert option.is_selected() is True def test_should_select_first_option_if_none_is_selected(driver, pages): pages.load("formPage.html") selectBox = driver.find_element(By.XPATH, "//select[@name='select-default']") options = selectBox.find_elements(By.TAG_NAME, "option") one = options[0] two = options[1] assert one.is_selected() is True assert two.is_selected() is False two.click() assert one.is_selected() is False assert two.is_selected() is True def test_can_select_elements_in_opt_group(driver, pages): pages.load("selectPage.html") element = driver.find_element(By.ID, "two-in-group") element.click() assert element.is_selected() is True def test_can_get_value_from_option_via_attribute_when_attribute_doesnt_exist(driver, pages): pages.load("formPage.html") element = driver.find_element(By.CSS_SELECTOR, "select[name='select-default'] option") assert element.get_attribute("value") == "One" element = driver.find_element(By.ID, "blankOption") assert element.get_attribute("value") == "" def test_can_get_value_from_option_via_attribute_when_attribute_is_empty_string(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "optionEmptyValueSet") assert element.get_attribute("value") == "" selenium-selenium-4.23.0/test/selenium/webdriver/common/executing_async_javascript_tests.py0000664000175000017500000002077614646203155032437 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import TimeoutException from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By from selenium.webdriver.remote.webelement import WebElement @pytest.fixture(autouse=True) def reset_timeouts(driver): driver.set_script_timeout(5) yield driver.set_script_timeout(30) def test_should_not_timeout_if_callback_invoked_immediately(driver, pages): pages.load("ajaxy_page.html") result = driver.execute_async_script("arguments[arguments.length - 1](123);") assert isinstance(result, int) assert 123 == result def test_should_be_able_to_return_javascript_primitives_from_async_scripts_neither_none_nor_undefined(driver, pages): pages.load("ajaxy_page.html") assert 123 == driver.execute_async_script("arguments[arguments.length - 1](123);") assert "abc" == driver.execute_async_script("arguments[arguments.length - 1]('abc');") assert not bool(driver.execute_async_script("arguments[arguments.length - 1](false);")) assert bool(driver.execute_async_script("arguments[arguments.length - 1](true);")) def test_should_be_able_to_return_javascript_primitives_from_async_scripts_null_and_undefined(driver, pages): pages.load("ajaxy_page.html") assert driver.execute_async_script("arguments[arguments.length - 1](null)") is None assert driver.execute_async_script("arguments[arguments.length - 1]()") is None def test_should_be_able_to_return_an_array_literal_from_an_async_script(driver, pages): pages.load("ajaxy_page.html") result = driver.execute_async_script("arguments[arguments.length - 1]([]);") assert "Expected not to be null!", result is not None assert isinstance(result, list) assert len(result) == 0 def test_should_be_able_to_return_an_array_object_from_an_async_script(driver, pages): pages.load("ajaxy_page.html") result = driver.execute_async_script("arguments[arguments.length - 1](new Array());") assert "Expected not to be null!", result is not None assert isinstance(result, list) assert len(result) == 0 def test_should_be_able_to_return_arrays_of_primitives_from_async_scripts(driver, pages): pages.load("ajaxy_page.html") result = driver.execute_async_script("arguments[arguments.length - 1]([null, 123, 'abc', true, false]);") assert result is not None assert isinstance(result, list) assert not bool(result.pop()) assert bool(result.pop()) assert "abc" == result.pop() assert 123 == result.pop() assert result.pop() is None assert len(result) == 0 def test_should_be_able_to_return_web_elements_from_async_scripts(driver, pages): pages.load("ajaxy_page.html") result = driver.execute_async_script("arguments[arguments.length - 1](document.body);") assert isinstance(result, WebElement) assert "body" == result.tag_name.lower() @pytest.mark.xfail_safari @pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4525") def test_should_be_able_to_return_arrays_of_web_elements_from_async_scripts(driver, pages): pages.load("ajaxy_page.html") result = driver.execute_async_script("arguments[arguments.length - 1]([document.body, document.body]);") assert result is not None assert isinstance(result, list) list_ = result assert 2 == len(list_) assert isinstance(list_[0], WebElement) assert isinstance(list_[1], WebElement) assert "body" == list_[0].tag_name # assert list_[0] == list_[1] def test_should_timeout_if_script_does_not_invoke_callback(driver, pages): pages.load("ajaxy_page.html") with pytest.raises(TimeoutException): # Script is expected to be async and explicitly callback, so this should timeout. driver.execute_async_script("return 1 + 2;") def test_should_timeout_if_script_does_not_invoke_callback_with_azero_timeout(driver, pages): pages.load("ajaxy_page.html") with pytest.raises(TimeoutException): driver.execute_async_script("window.setTimeout(function() {}, 0);") def test_should_not_timeout_if_script_callsback_inside_azero_timeout(driver, pages): pages.load("ajaxy_page.html") driver.execute_async_script( """var callback = arguments[arguments.length - 1]; window.setTimeout(function() { callback(123); }, 0)""" ) def test_should_timeout_if_script_does_not_invoke_callback_with_long_timeout(driver, pages): driver.set_script_timeout(0.5) pages.load("ajaxy_page.html") with pytest.raises(TimeoutException): driver.execute_async_script( """var callback = arguments[arguments.length - 1]; window.setTimeout(callback, 1500);""" ) def test_should_detect_page_loads_while_waiting_on_an_async_script_and_return_an_error(driver, pages): pages.load("ajaxy_page.html") driver.set_script_timeout(0.1) with pytest.raises(WebDriverException): url = pages.url("dynamic.html") driver.execute_async_script(f"window.location = '{url}';") def test_should_catch_errors_when_executing_initial_script(driver, pages): pages.load("ajaxy_page.html") with pytest.raises(WebDriverException): driver.execute_async_script("throw Error('you should catch this!');") def test_should_be_able_to_execute_asynchronous_scripts(driver, pages): pages.load("ajaxy_page.html") typer = driver.find_element(by=By.NAME, value="typer") typer.send_keys("bob") assert "bob" == typer.get_attribute("value") driver.find_element(by=By.ID, value="red").click() driver.find_element(by=By.NAME, value="submit").click() assert 1 == len( driver.find_elements(by=By.TAG_NAME, value="div") ), "There should only be 1 DIV at this point, which is used for the butter message" driver.set_script_timeout(10) text = driver.execute_async_script( """var callback = arguments[arguments.length - 1]; window.registerListener(arguments[arguments.length - 1]);""" ) assert "bob" == text assert "" == typer.get_attribute("value") assert 2 == len( driver.find_elements(by=By.TAG_NAME, value="div") ), "There should be 1 DIV (for the butter message) + 1 DIV (for the new label)" def test_should_be_able_to_pass_multiple_arguments_to_async_scripts(driver, pages): pages.load("ajaxy_page.html") result = driver.execute_async_script( """ arguments[arguments.length - 1](arguments[0] + arguments[1]);""", 1, 2, ) assert 3 == result # TODO DavidBurns Disabled till Java WebServer is used # def test_should_be_able_to_make_xmlhttp_requests_and_wait_for_the_response(driver, pages): # script = """ # var url = arguments[0]; # var callback = arguments[arguments.length - 1]; # // Adapted from http://www.quirksmode.org/js/xmlhttp.html # var XMLHttpFactories = [ # function () return new XMLHttpRequest(), # function () return new ActiveXObject('Msxml2.XMLHTTP'), # function () return new ActiveXObject('Msxml3.XMLHTTP'), # function () return new ActiveXObject('Microsoft.XMLHTTP') # ]; # var xhr = false; # while (!xhr && XMLHttpFactories.length) # try{ # xhr = XMLHttpFactories.shift().call(); # }catch (e) # # if (!xhr) throw Error('unable to create XHR object'); # xhr.open('GET', url, true); # xhr.onreadystatechange = function() # if (xhr.readyState == 4) callback(xhr.responseText); # # xhr.send('');""" # empty string to stop firefox 3 from choking # # pages.load("ajaxy_page.html") # driver.set_script_timeout(3) # response = driver.execute_async_script(script, pages.sleepingPage + "?time=2") # htm = "DoneSlept for 2s" # assert response.strip() == htm selenium-selenium-4.23.0/test/selenium/webdriver/common/timeout_tests.py0000664000175000017500000000436214646203155026500 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.timeouts import Timeouts def test_should_create_timeouts_object(): implicit_wait = 10 page_load = 10 script = 10 timeouts = Timeouts(implicit_wait=implicit_wait, page_load=page_load, script=script) assert implicit_wait == timeouts.implicit_wait assert page_load == timeouts.page_load assert script == timeouts.script def test_should_error_if_implicit_wait_isnt_a_number(): with pytest.raises(TypeError): Timeouts(implicit_wait="abc") timeout = Timeouts(implicit_wait=0) with pytest.raises(TypeError): timeout.implicit_wait = "abc" def test_should_error_if_page_load_isnt_a_number(): with pytest.raises(TypeError): Timeouts(page_load="abc") timeout = Timeouts(page_load=0) with pytest.raises(TypeError): timeout.page_load = "abc" def test_should_error_if_script_isnt_a_number(): with pytest.raises(TypeError): Timeouts(script="abc") timeout = Timeouts(script=0) with pytest.raises(TypeError): timeout.script = "abc" def test_should_get_timeouts_without_setting_them(driver): results = driver.timeouts assert results.implicit_wait == 0 assert results.page_load == 300 assert results.script == 30 def test_should_set_and_get_timeouts_on_remote_end(driver): timeout = Timeouts(implicit_wait=10) driver.timeouts = timeout result = driver.timeouts assert result.implicit_wait == timeout.implicit_wait selenium-selenium-4.23.0/test/selenium/webdriver/common/driver_finder_tests.py0000664000175000017500000000530714646203155027634 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from pathlib import Path from unittest import mock import pytest from selenium import webdriver from selenium.common.exceptions import NoSuchDriverException from selenium.webdriver.common.driver_finder import DriverFinder def test_get_results_with_valid_path(): options = webdriver.ChromeOptions() service = webdriver.ChromeService(executable_path="/valid/path/to/driver") with mock.patch.object(Path, "is_file", return_value=True): result = DriverFinder(service, options).get_driver_path() assert result == "/valid/path/to/driver" def test_errors_with_invalid_path(): options = webdriver.ChromeOptions() service = webdriver.ChromeService(executable_path="/invalid/path/to/driver") with mock.patch.object(Path, "is_file", return_value=False): with pytest.raises(NoSuchDriverException) as excinfo: DriverFinder(service, options).get_driver_path() assert "Unable to obtain driver for chrome; For documentation on this error" in str(excinfo.value) def test_wraps_error_from_se_manager(): options = webdriver.ChromeOptions() service = webdriver.ChromeService(executable_path="/valid/path/to/driver") lib_path = "selenium.webdriver.common.selenium_manager.SeleniumManager" with mock.patch(lib_path + ".binary_paths", side_effect=Exception("Error")): with pytest.raises(NoSuchDriverException): DriverFinder(service, options).get_driver_path() def test_get_results_from_se_manager(monkeypatch): executable_path = "/invalid/path/to/driver" options = webdriver.ChromeOptions() service = webdriver.ChromeService(executable_path=executable_path) monkeypatch.setattr(Path, "is_file", lambda _: True) lib_path = "selenium.webdriver.common.selenium_manager.SeleniumManager" with mock.patch(lib_path + ".binary_paths", return_value=executable_path): path = DriverFinder(service, options).get_driver_path() assert path == executable_path selenium-selenium-4.23.0/test/selenium/webdriver/common/virtual_authenticator_tests.py0000664000175000017500000003225114646203155031430 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from base64 import b64decode from base64 import urlsafe_b64decode from typing import List import pytest from selenium.common.exceptions import InvalidArgumentException from selenium.webdriver.common.virtual_authenticator import Credential from selenium.webdriver.common.virtual_authenticator import VirtualAuthenticatorOptions from selenium.webdriver.remote.webdriver import WebDriver # working Key BASE64__ENCODED_PK = """ MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDbBOu5Lhs4vpowbCnmCyLUpIE7JM9sm9QXzye2G+jr+Kr MsinWohEce47BFPJlTaDzHSvOW2eeunBO89ZcvvVc8RLz4qyQ8rO98xS1jtgqi1NcBPETDrtzthODu/gd0sjB2Tk3TLuBGV oPXt54a+Oo4JbBJ6h3s0+5eAfGplCbSNq6hN3Jh9YOTw5ZA6GCEy5l8zBaOgjXytd2v2OdSVoEDNiNQRkjJd2rmS2oi9AyQ FR3B7BrPSiDlCcITZFOWgLF5C31Wp/PSHwQhlnh7/6YhnE2y9tzsUvzx0wJXrBADW13+oMxrneDK3WGbxTNYgIi1PvSqXlq GjHtCK+R2QkXAgMBAAECggEAVc6bu7VAnP6v0gDOeX4razv4FX/adCao9ZsHZ+WPX8PQxtmWYqykH5CY4TSfsuizAgyPuQ0 +j4Vjssr9VODLqFoanspT6YXsvaKanncUYbasNgUJnfnLnw3an2XpU2XdmXTNYckCPRX9nsAAURWT3/n9ljc/XYY22ecYxM 8sDWnHu2uKZ1B7M3X60bQYL5T/lVXkKdD6xgSNLeP4AkRx0H4egaop68hoW8FIwmDPVWYVAvo8etzWCtibRXz5FcNld9MgD /Ai7ycKy4Q1KhX5GBFI79MVVaHkSQfxPHpr7/XcmpQOEAr+BMPon4s4vnKqAGdGB3j/E3d/+4F2swykoQKBgQD8hCsp6FIQ 5umJlk9/j/nGsMl85LgLaNVYpWlPRKPc54YNumtvj5vx1BG+zMbT7qIE3nmUPTCHP7qb5ERZG4CdMCS6S64/qzZEqijLCqe pwj6j4fV5SyPWEcpxf6ehNdmcfgzVB3Wolfwh1ydhx/96L1jHJcTKchdJJzlfTvq8wwKBgQDeCnKws1t5GapfE1rmC/h4ol L2qZTth9oQmbrXYohVnoqNFslDa43ePZwL9Jmd9kYb0axOTNMmyrP0NTj41uCfgDS0cJnNTc63ojKjegxHIyYDKRZNVUR/d xAYB/vPfBYZUS7M89pO6LLsHhzS3qpu3/hppo/Uc/AM/r8PSflNHQKBgDnWgBh6OQncChPUlOLv9FMZPR1ZOfqLCYrjYEqi uzGm6iKM13zXFO4AGAxu1P/IAd5BovFcTpg79Z8tWqZaUUwvscnl+cRlj+mMXAmdqCeO8VASOmqM1ml667axeZDIR867ZG8 K5V029Wg+4qtX5uFypNAAi6GfHkxIKrD04yOHAoGACdh4wXESi0oiDdkz3KOHPwIjn6BhZC7z8mx+pnJODU3cYukxv3WTct lUhAsyjJiQ/0bK1yX87ulqFVgO0Knmh+wNajrb9wiONAJTMICG7tiWJOm7fW5cfTJwWkBwYADmkfTRmHDvqzQSSvoC2S7aa 9QulbC3C/qgGFNrcWgcT9kCgYAZTa1P9bFCDU7hJc2mHwJwAW7/FQKEJg8SL33KINpLwcR8fqaYOdAHWWz636osVEqosRrH zJOGpf9x2RSWzQJ+dq8+6fACgfFZOVpN644+sAHfNPAI/gnNKU5OfUv+eav8fBnzlf1A3y3GIkyMyzFN3DE7e0n/lyqxE4H BYGpI8g== """ REGISTER_CREDENTIAL = "registerCredential().then(arguments[arguments.length - 1]);" GET_CREDENTIAL = """getCredential([{ "type": "public-key", "id": Int8Array.from(arguments[0]), }]).then(arguments[arguments.length - 1]);""" def create_rk_enabled_u2f_authenticator(driver) -> WebDriver: options = VirtualAuthenticatorOptions() options.protocol = VirtualAuthenticatorOptions.Protocol.U2F options.has_resident_key = True driver.add_virtual_authenticator(options) return driver def create_rk_disabled_u2f_authenticator(driver) -> WebDriver: options = VirtualAuthenticatorOptions() options.protocol = VirtualAuthenticatorOptions.Protocol.U2F options.has_resident_key = False driver.add_virtual_authenticator(options) return driver def create_rk_enabled_ctap2_authenticator(driver) -> WebDriver: options = VirtualAuthenticatorOptions() options.protocol = VirtualAuthenticatorOptions.Protocol.CTAP2 options.has_resident_key = True options.has_user_verification = True options.is_user_verified = True driver.add_virtual_authenticator(options) return driver def create_rk_disabled_ctap2_authenticator(driver) -> WebDriver: options = VirtualAuthenticatorOptions() options.protocol = VirtualAuthenticatorOptions.Protocol.CTAP2 options.transport = VirtualAuthenticatorOptions.Transport.USB options.has_resident_key = False options.has_user_verification = True options.is_user_verified = True driver.add_virtual_authenticator(options) return driver def get_assertion_for(webdriver: WebDriver, credential_id: List[int]): return webdriver.execute_async_script(GET_CREDENTIAL, credential_id) def extract_id(response): return response.get("credential", {}).get("id", "") def extract_raw_id(response): return response.get("credential", {}).get("rawId", "") def not_allowed_error_in(response) -> bool: return response.get("status", "").startswith("NotAllowedError") # ---------------- TESTS ------------------------------------ @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_add_and_remove_virtual_authenticator(driver, pages): driver = create_rk_disabled_ctap2_authenticator(driver) driver.get(pages.url("virtual-authenticator.html", localhost=True)) result = driver.execute_async_script(REGISTER_CREDENTIAL) assert result.get("status", "") == "OK" assert get_assertion_for(driver, result["credential"]["rawId"]).get("status", "") == "OK" assert driver.virtual_authenticator_id is not None driver.remove_virtual_authenticator() assert driver.virtual_authenticator_id is None @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_add_and_remove_non_resident_credentials(driver, pages): driver = create_rk_disabled_ctap2_authenticator(driver) driver.get(pages.url("virtual-authenticator.html", localhost=True)) assert driver.virtual_authenticator_id is not None credential = Credential.create_non_resident_credential( bytearray({1, 2, 3, 4}), "localhost", b64decode(BASE64__ENCODED_PK), 0, ) driver.add_credential(credential) assert get_assertion_for(driver, [1, 2, 3, 4]).get("status", "") == "OK" driver.remove_virtual_authenticator() assert driver.virtual_authenticator_id is None @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_add_non_resident_credential_when_authenticator_uses_u2f_protocol(driver, pages): driver = create_rk_disabled_u2f_authenticator(driver) driver.get(pages.url("virtual-authenticator.html", localhost=True)) base64_pk = """ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg8_zMDQDYAxlU-Q hk1Dwkf0v18GZca1DMF3SaJ9HPdmShRANCAASNYX5lyVCOZLzFZzrIKmeZ2jwU RmgsJYxGP__fWN_S-j5sN4tT15XEpN_7QZnt14YvI6uvAgO0uJEboFaZlOEB """ credential = Credential.create_non_resident_credential( bytearray({1, 2, 3, 4}), "localhost", urlsafe_b64decode(base64_pk), 0, ) driver.add_credential(credential) assert get_assertion_for(driver, [1, 2, 3, 4]).get("status", "") == "OK" driver.remove_virtual_authenticator() @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_add_resident_credential_not_supported_when_authenticator_uses_u2f_protocol(driver, pages): driver = create_rk_enabled_u2f_authenticator(driver) driver.get(pages.url("virtual-authenticator.html", localhost=True)) base64_pk = """ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg8_zMDQDYAxlU-Q hk1Dwkf0v18GZca1DMF3SaJ9HPdmShRANCAASNYX5lyVCOZLzFZzrIKmeZ2jwU RmgsJYxGP__fWN_S-j5sN4tT15XEpN_7QZnt14YvI6uvAgO0uJEboFaZlOEB """ credential = Credential.create_resident_credential( bytearray({1, 2, 3, 4}), "localhost", bytearray({1}), urlsafe_b64decode(base64_pk), 0, ) with pytest.raises(InvalidArgumentException): driver.add_credential(credential) driver.remove_virtual_authenticator() @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_get_credentials(driver, pages): driver = create_rk_enabled_ctap2_authenticator(driver) driver.get(pages.url("virtual-authenticator.html", localhost=True)) # Register a Resident Credential response1 = driver.execute_async_script( """ registerCredential({authenticatorSelection: {requireResidentKey: true}}) .then(arguments[arguments.length - 1]); """ ) assert response1.get("status", "") == "OK" # Register a Non-Resident Credential response2 = driver.execute_async_script(REGISTER_CREDENTIAL) assert response2.get("status", "") == "OK" assert extract_id(response1) != extract_id(response2) # Retrieve the two credentials credentials = driver.get_credentials() assert len(credentials) == 2 credential1, credential2 = None, None for credential in credentials: # Using startswith because there can be padding difference '==' or '=' in the end if credential.id.startswith(extract_id(response1)): credential1: Credential = credential elif credential.id.startswith(extract_id(response2)): credential2: Credential = credential else: assert False, "Unknown credential" assert credential1.is_resident_credential, "Credential1 should be resident credential" assert credential1.private_key is not None, "Credential1 should have private key" assert credential2.is_resident_credential is False, "Credential2 should not be resident credential" assert credential2.private_key is not None, "Credential2 should have private key" assert credential2.sign_count == 1 driver.remove_virtual_authenticator() @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_remove_credential_by_raw_Id(driver, pages): driver = create_rk_disabled_u2f_authenticator(driver) driver.get(pages.url("virtual-authenticator.html", localhost=True)) # register a credential response = driver.execute_async_script(REGISTER_CREDENTIAL) assert response.get("status", "") == "OK" # remove the credential using array of bytes: rawId raw_id = extract_raw_id(response) driver.remove_credential(bytearray(raw_id)) # Trying to get the assertion should fail response = get_assertion_for(driver, raw_id) assert not_allowed_error_in(response), "Should have thrown a NotAllowedError" driver.remove_virtual_authenticator() @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_remove_credential_by_b64_urlId(driver, pages): driver = create_rk_disabled_u2f_authenticator(driver) driver.get(pages.url("virtual-authenticator.html", localhost=True)) # register a credential response = driver.execute_async_script(REGISTER_CREDENTIAL) assert response.get("status", "") == "OK" # remove the credential using array of bytes: rawId raw_id = extract_raw_id(response) credential_id = extract_id(response) driver.remove_credential(credential_id) # Trying to get the assertion should fail response = get_assertion_for(driver, raw_id) assert not_allowed_error_in(response), "Should have thrown a NotAllowedError" driver.remove_virtual_authenticator() @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_remove_all_credentials(driver, pages): driver = create_rk_disabled_u2f_authenticator(driver) driver.get(pages.url("virtual-authenticator.html", localhost=True)) # Register 2 credentials response1 = driver.execute_async_script(REGISTER_CREDENTIAL) raw_id1 = response1["credential"]["rawId"] response2 = driver.execute_async_script(REGISTER_CREDENTIAL) raw_id2 = response2["credential"]["rawId"] driver.remove_all_credentials() response = driver.execute_async_script( """ getCredential([{ "type": "public-key", "id": Int8Array.from(arguments[0]), }, { "type": "public-key", "id": Int8Array.from(arguments[1]), }]).then(arguments[arguments.length - 1]); """, raw_id1, raw_id2, ) assert not_allowed_error_in(response), "Should have thrown a NotAllowedError" driver.remove_virtual_authenticator() @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_set_user_verified(driver, pages): driver = create_rk_enabled_ctap2_authenticator(driver) driver.get(pages.url("virtual-authenticator.html", localhost=True)) # Register a credential requiring UV. response = driver.execute_async_script( "registerCredential({authenticatorSelection: {userVerification: 'required'}}).then(arguments[arguments.length - 1]);" ) assert response.get("status", "") == "OK" raw_id = response["credential"]["rawId"] # Getting an assertion requiring user verification should succeed. response = driver.execute_async_script(GET_CREDENTIAL, raw_id) assert response.get("status", "") == "OK" # Disable user verified. driver.set_user_verified(False) # Getting an assertion requiring user verification should fail. response = driver.execute_async_script(GET_CREDENTIAL, raw_id) assert not_allowed_error_in(response), "Should have thrown a NotAllowedError" driver.remove_virtual_authenticator() selenium-selenium-4.23.0/test/selenium/webdriver/common/form_handling_tests.py0000664000175000017500000001754314646203155027626 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait def test_should_click_on_submit_input_elements(driver, pages): pages.load("formPage.html") driver.find_element(By.ID, "submitButton").click() WebDriverWait(driver, 3).until(EC.title_is("We Arrive Here")) def test_clicking_on_unclickable_elements_does_nothing(driver, pages): pages.load("formPage.html") driver.find_element(By.XPATH, "//body").click() def test_should_be_able_to_click_image_buttons(driver, pages): pages.load("formPage.html") driver.find_element(By.ID, "imageButton").click() WebDriverWait(driver, 3).until(EC.title_is("We Arrive Here")) def test_should_submit_input_in_form(driver, pages): pages.load("formPage.html") driver.find_element(By.NAME, "login").submit() WebDriverWait(driver, 3).until(EC.title_is("We Arrive Here")) def test_should_submit_any_input_element_within_form(driver, pages): pages.load("formPage.html") driver.find_element(By.ID, "checky").submit() WebDriverWait(driver, 3).until(EC.title_is("We Arrive Here")) def test_should_submit_any_element_within_form(driver, pages): pages.load("formPage.html") driver.find_element(By.XPATH, "//form/p").submit() WebDriverWait(driver, 5).until(EC.title_is("We Arrive Here")) def test_should_submit_element_with_id_submit(driver, pages): pages.load("formPage.html") driver.find_element(By.ID, "submit").submit() WebDriverWait(driver, 5).until(EC.title_is("We Arrive Here")) def test_should_submit_element_with_name_submit(driver, pages): pages.load("formPage.html") driver.find_element(By.NAME, "submit").submit() WebDriverWait(driver, 5).until(EC.title_is("We Arrive Here")) def test_should_not_submit_button_outside_form(driver, pages): pages.load("formPage.html") with pytest.raises(WebDriverException): driver.find_element(By.NAME, "SearchableText").submit() def test_should_be_able_to_enter_text_into_atext_area_by_setting_its_value(driver, pages): pages.load("javascriptPage.html") textarea = driver.find_element(By.ID, "keyUpArea") cheesey = "Brie and cheddar" textarea.send_keys(cheesey) assert textarea.get_attribute("value") == cheesey def test_should_enter_data_into_form_fields(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.XPATH, "//form[@name='someForm']/input[@id='username']") originalValue = element.get_attribute("value") assert originalValue == "change" element.clear() element.send_keys("some text") element = driver.find_element(By.XPATH, "//form[@name='someForm']/input[@id='username']") newFormValue = element.get_attribute("value") assert newFormValue == "some text" def test_should_be_able_to_select_acheck_box(driver, pages): pages.load("formPage.html") checkbox = driver.find_element(By.ID, "checky") assert checkbox.is_selected() is False checkbox.click() assert checkbox.is_selected() is True checkbox.click() assert checkbox.is_selected() is False def test_should_toggle_the_checked_state_of_acheckbox(driver, pages): pages.load("formPage.html") checkbox = driver.find_element(By.ID, "checky") assert checkbox.is_selected() is False checkbox.click() assert checkbox.is_selected() is True checkbox.click() assert checkbox.is_selected() is False def test_toggling_acheckbox_should_return_its_current_state(driver, pages): pages.load("formPage.html") checkbox = driver.find_element(By.ID, "checky") assert checkbox.is_selected() is False checkbox.click() assert checkbox.is_selected() is True checkbox.click() assert checkbox.is_selected() is False def test_should_be_able_to_select_aradio_button(driver, pages): pages.load("formPage.html") radioButton = driver.find_element(By.ID, "peas") assert radioButton.is_selected() is False radioButton.click() assert radioButton.is_selected() is True def test_should_be_able_to_select_aradio_button_by_clicking_on_it(driver, pages): pages.load("formPage.html") radioButton = driver.find_element(By.ID, "peas") assert radioButton.is_selected() is False radioButton.click() assert radioButton.is_selected() is True def test_should_return_state_of_radio_buttons_before_interaction(driver, pages): pages.load("formPage.html") radioButton = driver.find_element(By.ID, "cheese_and_peas") assert radioButton.is_selected() is True radioButton = driver.find_element(By.ID, "cheese") assert radioButton.is_selected() is False def test_toggling_an_option_should_toggle_options_in_amulti_select(driver, pages): pages.load("formPage.html") select = driver.find_element(By.NAME, "multi") option = select.find_elements(By.TAG_NAME, "option")[0] selected = option.is_selected() option.click() assert not selected == option.is_selected() option.click() assert selected == option.is_selected() def test_should_throw_an_exception_when_selecting_an_unselectable_element(driver, pages): pages.load("formPage.html") element = driver.find_element(By.XPATH, "//title") with pytest.raises(WebDriverException): element.click() def test_sending_keyboard_events_should_append_text_in_inputs(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "working") element.send_keys("Some") value = element.get_attribute("value") assert value == "Some" element.send_keys(" text") value = element.get_attribute("value") assert value == "Some text" def test_should_be_able_to_clear_text_from_input_elements(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "working") element.send_keys("Some text") value = element.get_attribute("value") assert len(value) > 0 element.clear() value = element.get_attribute("value") assert len(value) == 0 def test_empty_text_boxes_should_return_an_empty_string_not_null(driver, pages): pages.load("formPage.html") emptyTextBox = driver.find_element(By.ID, "working") assert emptyTextBox.get_attribute("value") == "" emptyTextArea = driver.find_element(By.ID, "emptyTextArea") assert emptyTextArea.get_attribute("value") == "" def test_should_be_able_to_clear_text_from_text_areas(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "withText") element.send_keys("Some text") value = element.get_attribute("value") assert len(value) > 0 element.clear() value = element.get_attribute("value") assert len(value) == 0 def test_radio_should_not_be_selected_after_selecting_sibling(driver, pages): pages.load("formPage.html") cheese = driver.find_element(By.ID, "cheese") peas = driver.find_element(By.ID, "peas") cheese.click() assert cheese.is_selected() is True assert peas.is_selected() is False peas.click() assert cheese.is_selected() is False assert peas.is_selected() is True selenium-selenium-4.23.0/test/selenium/webdriver/common/results_page.py0000664000175000017500000000265014646203155026263 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from selenium.webdriver.common.by import By class ResultsPage: """This class models a google search result page.""" def __init__(self, driver): self._driver = driver def is_loaded(self): return "/search" in self._driver.get_current_url() def load(self): raise Exception("This page shouldn't be loaded directly") def link_contains_match_for(self, term): result_section = self._driver.find_element(By.ID, "res") elements = result_section.find_elements(By.XPATH, ".//*[@class='l']") for e in elements: if term in e.get_text(): return True return False selenium-selenium-4.23.0/test/selenium/webdriver/common/quit_tests.py0000664000175000017500000000167714646203155026002 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest @pytest.mark.no_driver_after_test def test_quit(driver, pages): driver.quit() with pytest.raises(Exception): pages.load("simpleTest.html") selenium-selenium-4.23.0/test/selenium/webdriver/common/network.py0000664000175000017500000000424214646203155025256 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # module for getting the lan ip address of the computer import os import socket if os.name != "nt": import fcntl import struct def get_interface_ip(ifname): def _bytes(value, encoding): try: return bytes(value, encoding) # Python 3 except TypeError: return value # Python 2 sckt = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) return socket.inet_ntoa( fcntl.ioctl(sckt.fileno(), 0x8915, struct.pack("256s", _bytes(ifname[:15], "utf-8")))[20:24] # SIOCGIFADDR ) def get_lan_ip(): if os.environ.get("CI") == "true": return "0.0.0.0" try: ip = socket.gethostbyname(socket.gethostname()) except Exception: return "0.0.0.0" if ip.startswith("127.") and os.name != "nt": interfaces = [ "eth0", "eth1", "eth2", "en0", "en1", "en2", "en3", "en4", "eno0", "eno1", "eno2", "eno3", "eno4", "wlan0", "wlan1", "wifi0", "ath0", "ath1", "ppp0", ] for ifname in interfaces: try: ip = get_interface_ip(ifname) break except OSError: pass return ip selenium-selenium-4.23.0/test/selenium/webdriver/common/test_file2.txt0000664000175000017500000000003314646203155026006 0ustar carstencarstenlorem ipsum dolor sit amet selenium-selenium-4.23.0/test/selenium/webdriver/common/takes_screenshots_tests.py0000664000175000017500000000300114646203155030526 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import base64 import imghdr import pytest from selenium.webdriver.common.by import By def test_get_screenshot_as_base64(driver, pages): pages.load("simpleTest.html") result = base64.b64decode(driver.get_screenshot_as_base64()) assert imghdr.what("", result) == "png" def test_get_screenshot_as_png(driver, pages): pages.load("simpleTest.html") result = driver.get_screenshot_as_png() assert imghdr.what("", result) == "png" @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_get_element_screenshot(driver, pages): pages.load("simpleTest.html") element = driver.find_element(By.ID, "multiline") result = base64.b64decode(element.screenshot_as_base64) assert imghdr.what("", result) == "png" selenium-selenium-4.23.0/test/selenium/webdriver/common/conftest.py0000664000175000017500000000173514646203155025416 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. def pytest_generate_tests(metafunc): if "driver" in metafunc.fixturenames and metafunc.config.option.drivers: metafunc.parametrize("driver", metafunc.config.option.drivers, indirect=True) selenium-selenium-4.23.0/test/selenium/webdriver/common/webdriverwait_tests.py0000664000175000017500000003752314646203155027675 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import time import pytest from selenium.common.exceptions import InvalidElementStateException from selenium.common.exceptions import InvalidSelectorException from selenium.common.exceptions import StaleElementReferenceException from selenium.common.exceptions import TimeoutException from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait def throw_sere(driver): raise StaleElementReferenceException("test") @pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") @pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") def test_should_fail_with_invalid_selector_exception(driver, pages): pages.load("dynamic.html") with pytest.raises(InvalidSelectorException): WebDriverWait(driver, 0.7).until(EC.presence_of_element_located((By.XPATH, "//*[contains(@id,'something'"))) def test_should_explicitly_wait_for_a_single_element(driver, pages): pages.load("dynamic.html") add = driver.find_element(By.ID, "adder") add.click() WebDriverWait(driver, 3).until( EC.presence_of_element_located((By.ID, "box0")) ) # All is well if this doesn't throw. def test_should_still_fail_to_find_an_element_with_explicit_wait(driver, pages): pages.load("dynamic.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.presence_of_element_located((By.ID, "box0"))) def test_should_explicitly_wait_until_at_least_one_element_is_found_when_searching_for_many(driver, pages): pages.load("dynamic.html") add = driver.find_element(By.ID, "adder") add.click() add.click() elements = WebDriverWait(driver, 3).until(EC.presence_of_all_elements_located((By.CLASS_NAME, "redbox"))) assert len(elements) >= 1 def test_should_fail_to_find_elements_when_explicit_waiting(driver, pages): pages.load("dynamic.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.presence_of_all_elements_located((By.CLASS_NAME, "redbox"))) def test_should_wait_until_at_least_one_visible_elements_is_found_when_searching_for_many(driver, pages): pages.load("hidden_partially.html") add_visible = driver.find_element(By.ID, "addVisible") add_hidden = driver.find_element(By.ID, "addHidden") add_visible.click() add_visible.click() add_hidden.click() class wait_for_two_elements: def __init__(self, locator): self.locator = locator def __call__(self, driver): elements = [element for element in driver.find_elements(*self.locator) if EC._element_if_visible(element)] return elements if len(elements) == 2 else False elements = WebDriverWait(driver, 3).until(wait_for_two_elements((By.CLASS_NAME, "redbox"))) assert len(elements) == 2 def test_should_fail_to_find_visible_elements_when_explicit_waiting(driver, pages): pages.load("hidden_partially.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.visibility_of_any_elements_located((By.CLASS_NAME, "redbox"))) def test_should_wait_until_all_visible_elements_are_found_when_searching_for_many(driver, pages): pages.load("hidden_partially.html") add_visible = driver.find_element(By.ID, "addVisible") add_visible.click() add_visible.click() elements = WebDriverWait(driver, 3).until(EC.visibility_of_all_elements_located((By.CLASS_NAME, "redbox"))) assert len(elements) == 2 def test_should_fail_if_not_all_elements_are_visible(driver, pages): pages.load("hidden_partially.html") add_visible = driver.find_element(By.ID, "addVisible") add_hidden = driver.find_element(By.ID, "addHidden") add_visible.click() add_hidden.click() with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.visibility_of_all_elements_located((By.CLASS_NAME, "redbox"))) def test_should_wait_only_as_long_as_timeout_specified_when_implicit_waits_are_set(driver, pages): pages.load("dynamic.html") driver.implicitly_wait(0.5) start = time.time() with pytest.raises(TimeoutException): WebDriverWait(driver, 1).until(EC.presence_of_element_located((By.ID, "box0"))) assert time.time() - start < 1.5 def test_should_wait_at_least_once(driver, pages): pages.load("simpleTest.html") elements = WebDriverWait(driver, 0).until(lambda d: d.find_elements(By.TAG_NAME, "h1")) assert len(elements) >= 1 def test_wait_until_not_returns_if_evaluates_to_false(driver, pages): assert WebDriverWait(driver, 1).until_not(lambda d: False) is False def test_wait_should_still_fail_if_produce_ignored_exception(driver, pages): ignored = (InvalidElementStateException, StaleElementReferenceException) with pytest.raises(TimeoutException): WebDriverWait(driver, 1, 0.7, ignored_exceptions=ignored).until(throw_sere) def test_wait_should_still_fail_if_produce_child_of_ignored_exception(driver, pages): ignored = WebDriverException with pytest.raises(TimeoutException): WebDriverWait(driver, 1, 0.7, ignored_exceptions=ignored).until(throw_sere) def test_wait_until_not_should_not_fail_if_produce_ignored_exception(driver, pages): ignored = (InvalidElementStateException, StaleElementReferenceException) assert WebDriverWait(driver, 1, 0.7, ignored_exceptions=ignored).until_not(throw_sere) def test_expected_condition_title_is(driver, pages): pages.load("blank.html") WebDriverWait(driver, 1).until(EC.title_is("blank")) driver.execute_script("setTimeout(function(){document.title='not blank'}, 200)") WebDriverWait(driver, 2).until(EC.title_is("not blank")) assert driver.title == "not blank" with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.title_is("blank")) def test_expected_condition_title_contains(driver, pages): pages.load("blank.html") driver.execute_script("setTimeout(function(){document.title='not blank'}, 200)") WebDriverWait(driver, 2).until(EC.title_contains("not")) assert driver.title == "not blank" with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.title_contains("blanket")) @pytest.mark.xfail_safari def test_expected_condition_visibility_of_element_located(driver, pages): pages.load("javascriptPage.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.visibility_of_element_located((By.ID, "clickToHide"))) driver.find_element(By.ID, "clickToShow").click() element = WebDriverWait(driver, 5).until(EC.visibility_of_element_located((By.ID, "clickToHide"))) assert element.is_displayed() is True @pytest.mark.xfail_safari def test_expected_condition_visibility_of(driver, pages): pages.load("javascriptPage.html") hidden = driver.find_element(By.ID, "clickToHide") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.visibility_of(hidden)) driver.find_element(By.ID, "clickToShow").click() element = WebDriverWait(driver, 5).until(EC.visibility_of(hidden)) assert element.is_displayed() is True def test_expected_condition_text_to_be_present_in_element(driver, pages): pages.load("booleanAttributes.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.text_to_be_present_in_element((By.ID, "unwrappable"), "Expected")) driver.execute_script( "setTimeout(function(){var el = document.getElementById('unwrappable'); el.textContent = el.innerText = 'Unwrappable Expected text'}, 200)" ) WebDriverWait(driver, 2).until(EC.text_to_be_present_in_element((By.ID, "unwrappable"), "Expected")) assert "Unwrappable Expected text" == driver.find_element(By.ID, "unwrappable").text def test_expected_condition_text_to_be_present_in_element_value(driver, pages): pages.load("booleanAttributes.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 1).until(EC.text_to_be_present_in_element_value((By.ID, "inputRequired"), "Expected")) driver.execute_script( "setTimeout(function(){document.getElementById('inputRequired').value = 'Example Expected text'}, 200)" ) WebDriverWait(driver, 2).until(EC.text_to_be_present_in_element_value((By.ID, "inputRequired"), "Expected")) assert "Example Expected text" == driver.find_element(By.ID, "inputRequired").get_attribute("value") def test_expected_condition_text_to_be_present_in_element_attribute(driver, pages): pages.load("booleanAttributes.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 1).until( EC.text_to_be_present_in_element_attribute((By.ID, "inputRequired"), "value", "Expected") ) driver.execute_script( "setTimeout(function(){document.getElementById('inputRequired').value = 'Example Expected text'}, 200)" ) WebDriverWait(driver, 2).until( EC.text_to_be_present_in_element_attribute((By.ID, "inputRequired"), "value", "Expected") ) assert "Example Expected text" == driver.find_element(By.ID, "inputRequired").get_attribute("value") def test_expected_condition_frame_to_be_available_and_switch_to_it_by_locator(driver, pages): pages.load("blank.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 1).until(EC.frame_to_be_available_and_switch_to_it((By.ID, "myFrame"))) driver.execute_script( "setTimeout(function(){var f = document.createElement('iframe'); f.id='myFrame'; f.src = '" + pages.url("iframeWithAlert.html") + "'; document.body.appendChild(f)}, 200)" ) WebDriverWait(driver, 2).until(EC.frame_to_be_available_and_switch_to_it((By.ID, "myFrame"))) assert "click me" == driver.find_element(By.ID, "alertInFrame").text def test_expected_condition_invisiblity_of_element(driver, pages): pages.load("javascriptPage.html") target = driver.find_element(By.ID, "clickToHide") driver.execute_script("delayedShowHide(0, true)") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.invisibility_of_element(target)) driver.execute_script("delayedShowHide(200, false)") element = WebDriverWait(driver, 2).until(EC.invisibility_of_element(target)) assert element.is_displayed() is False assert target == element def test_expected_condition_invisiblity_of_element_located(driver, pages): pages.load("javascriptPage.html") driver.execute_script("delayedShowHide(0, true)") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.invisibility_of_element_located((By.ID, "clickToHide"))) driver.execute_script("delayedShowHide(200, false)") element = WebDriverWait(driver, 2).until(EC.invisibility_of_element_located((By.ID, "clickToHide"))) assert element.is_displayed() is False @pytest.mark.xfail_safari def test_expected_condition_element_to_be_clickable(driver, pages): pages.load("javascriptPage.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.element_to_be_clickable((By.ID, "clickToHide"))) driver.execute_script("delayedShowHide(200, true)") WebDriverWait(driver, 2).until(EC.element_to_be_clickable((By.ID, "clickToHide"))) element = driver.find_element(By.ID, "clickToHide") element.click() WebDriverWait(driver, 4.5).until(EC.invisibility_of_element_located((By.ID, "clickToHide"))) assert element.is_displayed() is False def test_expected_condition_staleness_of(driver, pages): pages.load("dynamicallyModifiedPage.html") element = driver.find_element(By.ID, "element-to-remove") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.staleness_of(element)) driver.find_element(By.ID, "buttonDelete").click() assert "element" == element.text WebDriverWait(driver, 2).until(EC.staleness_of(element)) with pytest.raises(StaleElementReferenceException): element.text def test_expected_condition_element_to_be_selected(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "checky") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.element_to_be_selected(element)) driver.execute_script("setTimeout(function(){document.getElementById('checky').checked = true}, 200)") WebDriverWait(driver, 2).until(EC.element_to_be_selected(element)) assert element.is_selected() is True def test_expected_condition_element_located_to_be_selected(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "checky") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.element_located_to_be_selected((By.ID, "checky"))) driver.execute_script("setTimeout(function(){document.getElementById('checky').checked = true}, 200)") WebDriverWait(driver, 2).until(EC.element_located_to_be_selected((By.ID, "checky"))) assert element.is_selected() is True def test_expected_condition_element_selection_state_to_be(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "checky") WebDriverWait(driver, 0.7).until(EC.element_selection_state_to_be(element, False)) assert element.is_selected() is False with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.element_selection_state_to_be(element, True)) driver.execute_script("setTimeout(function(){document.getElementById('checky').checked = true}, 200)") WebDriverWait(driver, 2).until(EC.element_selection_state_to_be(element, True)) assert element.is_selected() is True def test_expected_condition_element_located_selection_state_to_be(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "checky") WebDriverWait(driver, 0.7).until(EC.element_located_selection_state_to_be((By.ID, "checky"), False)) assert element.is_selected() is False with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.element_located_selection_state_to_be((By.ID, "checky"), True)) driver.execute_script("setTimeout(function(){document.getElementById('checky').checked = true}, 200)") WebDriverWait(driver, 2).until(EC.element_located_selection_state_to_be((By.ID, "checky"), True)) assert element.is_selected() is True def test_expected_condition_alert_is_present(driver, pages): pages.load("blank.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.alert_is_present()) driver.execute_script("setTimeout(function(){alert('alerty')}, 200)") WebDriverWait(driver, 2).until(EC.alert_is_present()) alert = driver.switch_to.alert assert "alerty" == alert.text alert.dismiss() def test_expected_condition_attribute_to_be_include_in_element(driver, pages): pages.load("booleanAttributes.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 1).until(EC.element_attribute_to_include((By.ID, "inputRequired"), "test")) value = WebDriverWait(driver, 2).until(EC.element_attribute_to_include((By.ID, "inputRequired"), "value")) assert value is not None selenium-selenium-4.23.0/test/selenium/webdriver/common/element_aria_tests.py0000664000175000017500000000341514646203155027435 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.by import By @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_should_return_explicitly_specified_role(driver): driver.get("data:text/html,
Level 1 Header
") header1 = driver.find_element(By.CSS_SELECTOR, "div") assert header1.aria_role == "heading" @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_should_return_implicit_role_defined_by_tag_name(driver): driver.get("data:text/html,

Level 1 Header

") header1 = driver.find_element(By.CSS_SELECTOR, "h1") assert header1.aria_role == "heading" @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_should_return_explicit_role_even_if_it_contradicts_tag_name(driver): driver.get("data:text/html,

Level 1 Header

") header1 = driver.find_element(By.CSS_SELECTOR, "h1") assert header1.aria_role == "alert" selenium-selenium-4.23.0/test/selenium/webdriver/common/correct_event_firing_tests.py0000664000175000017500000001151114646203155031204 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.by import By @pytest.mark.xfail_safari def test_should_fire_click_event_when_clicking(driver, pages): pages.load("javascriptPage.html") _click_on_element_which_records_events(driver) _assert_event_fired(driver, "click") @pytest.mark.xfail_safari def test_should_fire_mouse_down_event_when_clicking(driver, pages): pages.load("javascriptPage.html") _click_on_element_which_records_events(driver) _assert_event_fired(driver, "mousedown") @pytest.mark.xfail_safari def test_should_fire_mouse_up_event_when_clicking(driver, pages): pages.load("javascriptPage.html") _click_on_element_which_records_events(driver) _assert_event_fired(driver, "mouseup") @pytest.mark.xfail_safari def test_should_issue_mouse_down_events(driver, pages): pages.load("javascriptPage.html") driver.find_element(By.ID, "mousedown").click() result = driver.find_element(By.ID, "result").text assert result == "mouse down" @pytest.mark.xfail_safari def test_should_issue_click_events(driver, pages): pages.load("javascriptPage.html") driver.find_element(By.ID, "mouseclick").click() result = driver.find_element(By.ID, "result").text assert result == "mouse click" @pytest.mark.xfail_safari def test_should_issue_mouse_up_events(driver, pages): pages.load("javascriptPage.html") driver.find_element(By.ID, "mouseup").click() result = driver.find_element(By.ID, "result").text assert result == "mouse up" @pytest.mark.xfail_safari def test_mouse_events_should_bubble_up_to_containing_elements(driver, pages): pages.load("javascriptPage.html") driver.find_element(By.ID, "child").click() result = driver.find_element(By.ID, "result").text assert result == "mouse down" @pytest.mark.xfail_safari def test_should_emit_on_change_events_when_selecting_elements(driver, pages): pages.load("javascriptPage.html") select = driver.find_element(By.ID, "selector") options = select.find_elements(By.TAG_NAME, "option") initialTextValue = driver.find_element(By.ID, "result").text select.click() assert driver.find_element(By.ID, "result").text == initialTextValue options[1].click() assert driver.find_element(By.ID, "result").text == "bar" @pytest.mark.xfail_safari def test_should_emit_on_change_events_when_changing_the_state_of_acheckbox(driver, pages): pages.load("javascriptPage.html") checkbox = driver.find_element(By.ID, "checkbox") checkbox.click() assert driver.find_element(By.ID, "result").text == "checkbox thing" def test_should_emit_click_event_when_clicking_on_atext_input_element(driver, pages): pages.load("javascriptPage.html") clicker = driver.find_element(By.ID, "clickField") clicker.click() assert clicker.get_attribute("value") == "Clicked" @pytest.mark.xfail_safari def test_clearing_an_element_should_cause_the_on_change_handler_to_fire(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(By.ID, "clearMe") element.clear() result = driver.find_element(By.ID, "result") assert result.text == "Cleared" # TODO Currently Failing and needs fixing # def test_sending_keys_to_another_element_should_cause_the_blur_event_to_fire(driver, pages): # pages.load("javascriptPage.html") # element = driver.find_element(By.ID, "theworks") # element.send_keys("foo") # element2 = driver.find_element(By.ID, "changeable") # element2.send_keys("bar") # _assertEventFired(driver, "blur") # TODO Currently Failing and needs fixing # def test_sending_keys_to_an_element_should_cause_the_focus_event_to_fire(driver, pages): # pages.load("javascriptPage.html") # element = driver.find_element(By.ID, "theworks") # element.send_keys("foo") # _assertEventFired(driver, "focus") def _click_on_element_which_records_events(driver): driver.find_element(By.ID, "plainButton").click() def _assert_event_fired(driver, eventName): result = driver.find_element(By.ID, "result") text = result.text assert eventName in text, "No " + eventName + " fired: " + text selenium-selenium-4.23.0/test/selenium/webdriver/common/utils.py0000664000175000017500000000202114646203155024716 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. def convert_cookie_to_json(cookie): cookie_dict = {} for key, value in cookie.items(): if key == "expires": cookie_dict["expiry"] = int(value) * 1000 else: cookie_dict[key] = value return cookie_dict selenium-selenium-4.23.0/test/selenium/webdriver/common/window_tests.py0000664000175000017500000001412214646203155026314 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import WebDriverException from selenium.webdriver.support.wait import WebDriverWait # @pytest.mark.xfail_ie # @pytest.mark.xfail_edge(reason="Fails on Travis") # @pytest.mark.xfail_firefox(reason="Fails on Travis") # @pytest.mark.xfail_remote(reason="Fails on Travis") # def test_should_maximize_the_window(driver): # resize_timeout = 5 # wait = WebDriverWait(driver, resize_timeout) # old_size = driver.get_window_size() # driver.set_window_size(200, 200) # wait.until( # lambda dr: dr.get_window_size() != old_size if old_size["width"] != 200 and old_size["height"] != 200 else True) # size = driver.get_window_size() # driver.maximize_window() # wait.until(lambda dr: dr.get_window_size() != size) # new_size = driver.get_window_size() # assert new_size["width"] > size["width"] # assert new_size["height"] > size["height"] def test_should_get_the_size_of_the_current_window(driver): size = driver.get_window_size() assert size.get("width") > 0 assert size.get("height") > 0 def test_should_set_the_size_of_the_current_window(driver): size = driver.get_window_size() target_width = size.get("width") - 20 target_height = size.get("height") - 20 driver.set_window_size(width=target_width, height=target_height) new_size = driver.get_window_size() assert new_size.get("width") == target_width assert new_size.get("height") == target_height @pytest.mark.xfail_chrome def test_should_get_the_position_of_the_current_window(driver): position = driver.get_window_position() assert position.get("x") >= 0 assert position.get("y") >= 0 def test_should_set_the_position_of_the_current_window(driver): position = driver.get_window_position() target_x = position.get("x") + 10 target_y = position.get("y") + 10 driver.set_window_position(x=target_x, y=target_y) WebDriverWait(driver, 2).until( lambda d: d.get_window_position()["x"] != position["x"] and d.get_window_position()["y"] != position["y"] ) new_position = driver.get_window_position() assert new_position.get("x") == target_x assert new_position.get("y") == target_y @pytest.mark.xfail_safari(raises=WebDriverException, reason="Get Window Rect command not implemented") @pytest.mark.xfail_chrome def test_should_get_the_rect_of_the_current_window(driver): rect = driver.get_window_rect() assert rect.get("x") >= 0 assert rect.get("y") >= 0 assert rect.get("width") >= 0 assert rect.get("height") >= 0 @pytest.mark.xfail_safari(raises=WebDriverException, reason="Get Window Rect command not implemented") def test_should_set_the_rect_of_the_current_window(driver): rect = driver.get_window_rect() target_x = rect.get("x") + 10 target_y = rect.get("y") + 10 target_width = rect.get("width") + 10 target_height = rect.get("height") + 10 driver.set_window_rect(x=target_x, y=target_y, width=target_width, height=target_height) WebDriverWait(driver, 2).until( lambda d: d.get_window_position()["x"] != rect["x"] and d.get_window_position()["y"] != rect["y"] ) new_rect = driver.get_window_rect() assert new_rect.get("x") == target_x assert new_rect.get("y") == target_y assert new_rect.get("width") == target_width assert new_rect.get("height") == target_height def test_set_window_rect_should_accept_0_as_x_and_y(driver): from selenium.common.exceptions import InvalidArgumentException try: driver.set_window_rect(x=0, y=0) except InvalidArgumentException: pytest.fail("Should not have thrown InvalidArgumentException") def test_set_window_rect_throws_when_height_and_width_are_0(driver): from selenium.common.exceptions import InvalidArgumentException with pytest.raises(InvalidArgumentException): driver.set_window_rect(height=0, width=0) # @pytest.mark.xfail_safari(raises=WebDriverException, # reason='Fullscreen command not implemented') # @pytest.mark.skipif(os.environ.get('TRAVIS') == 'true', # reason='Fullscreen command causes Travis to hang') # @pytest.mark.no_driver_after_test # def test_should_fullscreen_the_current_window(driver): # start_width = driver.execute_script('return window.innerWidth;') # start_height = driver.execute_script('return window.innerHeight;') # driver.fullscreen_window() # WebDriverWait(driver, 2)\ # .until(lambda d: driver.execute_script('return window.innerWidth;') > start_width) # end_width = driver.execute_script('return window.innerWidth;') # end_height = driver.execute_script('return window.innerHeight;') # driver.quit() # Kill driver so we aren't running fullscreen after # assert end_width > start_width # assert end_height > start_height # @pytest.mark.xfail_safari(raises=WebDriverException, # reason='Minimize command not implemented') # @pytest.mark.skipif(os.environ.get('TRAVIS') == 'true', # reason='Minimize command causes Travis to hang') # @pytest.mark.no_driver_after_test # def test_should_minimize_the_current_window(driver): # driver.minimize_window() # minimized = driver.execute_script('return document.hidden;') # driver.quit() # Kill driver so we aren't running minimized after # assert minimized is True selenium-selenium-4.23.0/test/selenium/webdriver/common/text_handling_tests.py0000664000175000017500000001610214646203155027635 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.by import By newLine = "\n" def test_should_return_the_text_content_of_asingle_element_with_no_children(driver, pages): pages.load("simpleTest.html") selectText = driver.find_element(by=By.ID, value="oneline").text assert selectText == "A single line of text" getText = driver.find_element(by=By.ID, value="oneline").text assert getText == "A single line of text" def test_should_return_the_entire_text_content_of_child_elements(driver, pages): pages.load("simpleTest.html") text = driver.find_element(by=By.ID, value="multiline").text assert "A div containing" in text assert "More than one line of text" in text assert "and block level elements" in text @pytest.mark.xfail_safari def test_should_ignore_script_elements(driver, pages): pages.load("javascriptEnhancedForm.html") labelForUsername = driver.find_element(by=By.ID, value="labelforusername") text = labelForUsername.text assert len(labelForUsername.find_elements(by=By.TAG_NAME, value="script")) == 1 assert "document.getElementById" not in text assert text == "Username:" @pytest.mark.xfail_safari def test_should_represent_ablock_level_element_as_anewline(driver, pages): pages.load("simpleTest.html") text = driver.find_element(by=By.ID, value="multiline").text assert text.startswith("A div containing" + newLine) assert "More than one line of text" + newLine in text assert text.endswith("and block level elements") @pytest.mark.xfail_safari def test_should_collapse_multiple_whitespace_characters_into_asingle_space(driver, pages): pages.load("simpleTest.html") text = driver.find_element(by=By.ID, value="lotsofspaces").text assert text == "This line has lots of spaces." @pytest.mark.xfail_safari def test_should_trim_text(driver, pages): pages.load("simpleTest.html") text = driver.find_element(by=By.ID, value="multiline").text assert text.startswith("A div containing") assert text.endswith("block level elements") @pytest.mark.xfail_safari def test_should_convert_anon_breaking_space_into_anormal_space_character(driver, pages): pages.load("simpleTest.html") text = driver.find_element(by=By.ID, value="nbsp").text assert text == "This line has a non-breaking space" @pytest.mark.xfail_safari def test_should_treat_anon_breaking_space_as_any_other_whitespace_character_when_collapsing_whitespace(driver, pages): pages.load("simpleTest.html") element = driver.find_element(by=By.ID, value="nbspandspaces") text = element.text assert text == "This line has a non-breaking space and spaces" @pytest.mark.xfail_safari def test_having_inline_elements_should_not_affect_how_text_is_returned(driver, pages): pages.load("simpleTest.html") text = driver.find_element(by=By.ID, value="inline").text assert text == "This line has text within elements that are meant to be displayed inline" @pytest.mark.xfail_safari def test_should_return_the_entire_text_of_inline_elements(driver, pages): pages.load("simpleTest.html") text = driver.find_element(by=By.ID, value="span").text assert text == "An inline element" def test_should_be_able_to_set_more_than_one_line_of_text_in_atext_area(driver, pages): pages.load("formPage.html") textarea = driver.find_element(by=By.ID, value="withText") textarea.clear() expectedText = "I like cheese" + newLine + newLine + "It's really nice" textarea.send_keys(expectedText) seenText = textarea.get_attribute("value") assert seenText == expectedText def test_should_be_able_to_enter_dates_after_filling_in_other_values_first(driver, pages): pages.load("formPage.html") input_ = driver.find_element(by=By.ID, value="working") expectedValue = "10/03/2007 to 30/07/1993" input_.send_keys(expectedValue) seenValue = input_.get_attribute("value") assert seenValue == expectedValue @pytest.mark.xfail_safari def test_should_return_empty_string_when_text_is_only_spaces(driver, pages): pages.load("xhtmlTest.html") text = driver.find_element(by=By.ID, value="spaces").text assert text == "" def test_should_return_empty_string_when_text_is_empty(driver, pages): pages.load("xhtmlTest.html") text = driver.find_element(by=By.ID, value="empty").text assert text == "" @pytest.mark.xfail def test_should_return_empty_string_when_tag_is_self_closing(driver, pages): pages.load("xhtmlFormPage.xhtml") text = driver.find_element(by=By.ID, value="self-closed").text assert text == "" @pytest.mark.xfail_safari def test_should_handle_sibling_block_level_elements(driver, pages): pages.load("simpleTest.html") text = driver.find_element(by=By.ID, value="twoblocks").text assert text == "Some text" + newLine + "Some more text" @pytest.mark.xfail_safari def test_should_handle_whitespace_in_inline_elements(driver, pages): pages.load("simpleTest.html") text = driver.find_element(by=By.ID, value="inlinespan").text assert text == "line has text" def test_read_alarge_amount_of_data(driver, pages): pages.load("macbeth.html") source = driver.page_source.strip().lower() assert source.endswith("") @pytest.mark.xfail_safari def test_should_only_include_visible_text(driver, pages): pages.load("javascriptPage.html") empty = driver.find_element(by=By.ID, value="suppressedParagraph").text explicit = driver.find_element(by=By.ID, value="outer").text assert "" == empty assert "sub-element that is explicitly visible" == explicit @pytest.mark.xfail_safari def test_should_get_text_from_table_cells(driver, pages): pages.load("tables.html") tr = driver.find_element(by=By.ID, value="hidden_text") text = tr.text assert "some text" in text assert "some more text" not in text def test_should_get_text_which_is_avalid_jsonobject(driver, pages): pages.load("simpleTest.html") element = driver.find_element(by=By.ID, value="simpleJsonText") assert '{a="b", c=1, d=true}' == element.text # assert "{a=\"b\", \"c\"=d, e=true, f=\\123\\\\g\\\\\"\"\"\\\'}", element.text) def test_should_get_text_which_is_avalid_complex_jsonobject(driver, pages): pages.load("simpleTest.html") element = driver.find_element(by=By.ID, value="complexJsonText") assert """{a=\"\\\\b\\\\\\\"\'\\\'\"}""" == element.text selenium-selenium-4.23.0/test/selenium/webdriver/common/children_finding_tests.py0000664000175000017500000001531214646203155030275 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By def test_should_find_element_by_xpath(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "form2") child = element.find_element(By.XPATH, "select") assert child.get_attribute("id") == "2" def test_should_not_find_element_by_xpath(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "form2") with pytest.raises(NoSuchElementException): element.find_element(By.XPATH, "select/x") def test_finding_dot_slash_elements_on_element_by_xpath_should_find_not_top_level_elements(driver, pages): pages.load("simpleTest.html") parent = driver.find_element(By.ID, "multiline") children = parent.find_elements(By.XPATH, "./p") assert 1 == len(children) assert "A div containing" == children[0].text def test_should_find_elements_by_xpath(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "form2") children = element.find_elements(By.XPATH, "select/option") assert len(children) == 8 assert children[0].text == "One" assert children[1].text == "Two" def test_should_not_find_elements_by_xpath(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "form2") children = element.find_elements(By.XPATH, "select/x") assert len(children) == 0 def test_finding_elements_on_element_by_xpath_should_find_top_level_elements(driver, pages): pages.load("simpleTest.html") parent = driver.find_element(By.ID, "multiline") all_para_elements = driver.find_elements(By.XPATH, "//p") children = parent.find_elements(By.XPATH, "//p") assert len(all_para_elements) == len(children) def test_should_find_element_by_name(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "form2") child = element.find_element(By.NAME, "selectomatic") assert child.get_attribute("id") == "2" def test_should_find_elements_by_name(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "form2") children = element.find_elements(By.NAME, "selectomatic") assert len(children) == 2 def test_should_find_element_by_id(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "form2") child = element.find_element(By.ID, "2") assert child.get_attribute("name") == "selectomatic" def test_should_find_elements_by_id(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "form2") child = element.find_elements(By.ID, "2") assert len(child) == 2 def test_should_find_element_by_id_when_multiple_matches_exist(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.ID, "test_id_div") child = element.find_element(By.ID, "test_id") assert child.text == "inside" def test_should_find_element_by_id_when_no_match_in_context(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.ID, "test_id_div") with pytest.raises(NoSuchElementException): element.find_element(By.ID, "test_id_out") def test_should_find_element_by_link_text(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "div1") child = element.find_element(By.LINK_TEXT, "hello world") assert child.get_attribute("name") == "link1" def test_should_find_elements_by_link_text(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "div1") children = element.find_elements(By.LINK_TEXT, "hello world") assert len(children) == 2 assert "link1" == children[0].get_attribute("name") assert "link2" == children[1].get_attribute("name") def test_should_find_element_by_class_name(driver, pages): pages.load("nestedElements.html") parent = driver.find_element(By.NAME, "classes") element = parent.find_element(By.CLASS_NAME, "one") assert "Find me" == element.text def test_should_find_elements_by_class_name(driver, pages): pages.load("nestedElements.html") parent = driver.find_element(By.NAME, "classes") elements = parent.find_elements(By.CLASS_NAME, "one") assert 2 == len(elements) def test_should_find_element_by_tag_name(driver, pages): pages.load("nestedElements.html") parent = driver.find_element(By.NAME, "div1") element = parent.find_element(By.TAG_NAME, "a") assert "link1" == element.get_attribute("name") def test_should_find_elements_by_tag_name(driver, pages): pages.load("nestedElements.html") parent = driver.find_element(By.NAME, "div1") elements = parent.find_elements(By.TAG_NAME, "a") assert 2 == len(elements) def test_should_be_able_to_find_an_element_by_css_selector(driver, pages): pages.load("nestedElements.html") parent = driver.find_element(By.NAME, "form2") element = parent.find_element(By.CSS_SELECTOR, '*[name="selectomatic"]') assert "2" == element.get_attribute("id") def test_should_be_able_to_find_multiple_elements_by_css_selector(driver, pages): pages.load("nestedElements.html") parent = driver.find_element(By.NAME, "form2") elements = parent.find_elements(By.CSS_SELECTOR, '*[name="selectomatic"]') assert 2 == len(elements) def test_should_throw_an_error_if_user_passes_in_invalid_by(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "form2") with pytest.raises(WebDriverException): element.find_element("foo", "bar") def test_should_throw_an_error_if_user_passes_in_invalid_by_when_find_elements(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "form2") with pytest.raises(WebDriverException): element.find_elements("foo", "bar") selenium-selenium-4.23.0/test/selenium/webdriver/common/webserver.py0000664000175000017500000001522714646203155025576 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """A simple web server for testing purpose. It serves the testing html pages that are needed by the webdriver unit tests.""" import contextlib import logging import os import re import threading try: from urllib import request as urllib_request except ImportError: import urllib as urllib_request try: from http.server import BaseHTTPRequestHandler from http.server import HTTPServer from socketserver import ThreadingMixIn except ImportError: from BaseHTTPServer import BaseHTTPRequestHandler from BaseHTTPServer import HTTPServer from SocketServer import ThreadingMixIn def updir(): dirname = os.path.dirname return dirname(dirname(__file__)) LOGGER = logging.getLogger(__name__) WEBDRIVER = os.environ.get("WEBDRIVER", updir()) HTML_ROOT = os.path.join(WEBDRIVER, "../../../../common/src/web") if not os.path.isdir(HTML_ROOT): message = ( "Can't find 'common_web' directory, try setting WEBDRIVER" " environment variable WEBDRIVER:" + WEBDRIVER + " HTML_ROOT:" + HTML_ROOT ) LOGGER.error(message) assert 0, message DEFAULT_HOST = "localhost" DEFAULT_HOST_IP = "127.0.0.1" DEFAULT_PORT = 8000 class HtmlOnlyHandler(BaseHTTPRequestHandler): """Http handler.""" def do_GET(self): """GET method handler.""" try: path = self.path[1:].split("?")[0] if path[:5] == "page/": html = """Page{page_number} Page number {page_number}

top """.format( page_number=path[5:] ) html = html.encode("utf-8") else: with open(os.path.join(HTML_ROOT, path), encoding="latin-1") as f: html = f.read().encode("utf-8") self.send_response(200) self.send_header("Content-type", "text/html") self.end_headers() self.wfile.write(html) except OSError: self.send_error(404, f"File Not Found: {path}") def do_POST(self): """POST method handler.""" try: remaining_bytes = int(self.headers["content-length"]) contents = "" line = self.rfile.readline() contents += line.decode("utf-8") remaining_bytes -= len(line) line = self.rfile.readline() contents += line.decode("utf-8") remaining_bytes -= len(line) fn = re.findall(r'Content-Disposition.*name="upload"; filename="(.*)"', line.decode("utf-8")) if not fn: self.send_error(500, f"File not found. {contents}") return line = self.rfile.readline() remaining_bytes -= len(line) contents += line.decode("utf-8") line = self.rfile.readline() remaining_bytes -= len(line) contents += line.decode("utf-8") preline = self.rfile.readline() remaining_bytes -= len(preline) while remaining_bytes > 0: line = self.rfile.readline() remaining_bytes -= len(line) contents += line.decode("utf-8") self.send_response(200) self.send_header("Content-type", "text/html") self.end_headers() self.wfile.write( f""" {contents} """.encode() ) except Exception as e: self.send_error(500, f"Error found: {e}") def log_message(self, format, *args): """Override default to avoid trashing stderr""" pass class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): pass class SimpleWebServer: """A very basic web server.""" def __init__(self, host=DEFAULT_HOST_IP, port=DEFAULT_PORT): self.stop_serving = False host = host port = port while True: try: self.server = ThreadedHTTPServer((host, port), HtmlOnlyHandler) self.host = host self.port = port break except OSError: LOGGER.debug(f"port {port} is in use, trying to next one") port += 1 self.thread = threading.Thread(target=self._run_web_server) def _run_web_server(self): """Runs the server loop.""" LOGGER.debug("web server started") while not self.stop_serving: self.server.handle_request() self.server.server_close() def start(self): """Starts the server.""" self.thread.start() def stop(self): """Stops the server.""" self.stop_serving = True with contextlib.suppress(IOError): _ = urllib_request.urlopen(f"http://{self.host}:{self.port}") def where_is(self, path, localhost=False) -> str: # True force serve the page from localhost if localhost: return f"http://{DEFAULT_HOST}:{self.port}/{path}" return f"http://{self.host}:{self.port}/{path}" def main(argv=None): from optparse import OptionParser from time import sleep if argv is None: import sys argv = sys.argv parser = OptionParser("%prog [options]") parser.add_option( "-p", "--port", dest="port", type="int", help=f"port to listen (default: {DEFAULT_PORT})", default=DEFAULT_PORT ) opts, args = parser.parse_args(argv[1:]) if args: parser.error("wrong number of arguments") # Will exit server = SimpleWebServer(port=opts.port) server.start() print(f"Server started on port {opts.port}, hit CTRL-C to quit") try: while 1: sleep(0.1) except KeyboardInterrupt: pass if __name__ == "__main__": main() selenium-selenium-4.23.0/test/selenium/webdriver/common/interactions_tests.py0000664000175000017500000003212414646203155027511 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """Tests for advanced user interactions.""" import pytest from selenium.common.exceptions import MoveTargetOutOfBoundsException from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.actions import interaction from selenium.webdriver.common.actions.wheel_input import ScrollOrigin from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.ui import WebDriverWait def perform_drag_and_drop_with_mouse(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" pages.load("draggableLists.html") dragReporter = driver.find_element(By.ID, "dragging_reports") toDrag = driver.find_element(By.ID, "rightitem-3") dragInto = driver.find_element(By.ID, "sortable1") holdItem = ActionChains(driver).click_and_hold(toDrag) moveToSpecificItem = ActionChains(driver).move_to_element(driver.find_element(By.ID, "leftitem-4")) moveToOtherList = ActionChains(driver).move_to_element(dragInto) drop = ActionChains(driver).release(dragInto) assert "Nothing happened." == dragReporter.text holdItem.perform() moveToSpecificItem.perform() moveToOtherList.perform() assert "Nothing happened. DragOut" == dragReporter.text drop.perform() @pytest.mark.xfail_safari def test_dragging_element_with_mouse_moves_it_to_another_list(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" perform_drag_and_drop_with_mouse(driver, pages) dragInto = driver.find_element(By.ID, "sortable1") assert 6 == len(dragInto.find_elements(By.TAG_NAME, "li")) @pytest.mark.xfail_safari def test_dragging_element_with_mouse_fires_events(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" perform_drag_and_drop_with_mouse(driver, pages) dragReporter = driver.find_element(By.ID, "dragging_reports") assert "Nothing happened. DragOut DropIn RightItem 3" == dragReporter.text def _is_element_available(driver, id): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" try: driver.find_element(By.ID, id) return True except Exception: return False @pytest.mark.xfail_safari def test_drag_and_drop(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" element_available_timeout = 15 wait = WebDriverWait(driver, element_available_timeout) pages.load("droppableItems.html") wait.until(lambda dr: _is_element_available(driver, "draggable")) if not _is_element_available(driver, "draggable"): raise AssertionError("Could not find draggable element after 15 seconds.") toDrag = driver.find_element(By.ID, "draggable") dropInto = driver.find_element(By.ID, "droppable") holdDrag = ActionChains(driver).click_and_hold(toDrag) move = ActionChains(driver).move_to_element(dropInto) drop = ActionChains(driver).release(dropInto) holdDrag.perform() move.perform() drop.perform() dropInto = driver.find_element(By.ID, "droppable") text = dropInto.find_element(By.TAG_NAME, "p").text assert "Dropped!" == text @pytest.mark.xfail_safari def test_double_click(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" pages.load("javascriptPage.html") toDoubleClick = driver.find_element(By.ID, "doubleClickField") dblClick = ActionChains(driver).double_click(toDoubleClick) dblClick.perform() assert "DoubleClicked" == toDoubleClick.get_attribute("value") def test_context_click(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" pages.load("javascriptPage.html") toContextClick = driver.find_element(By.ID, "doubleClickField") contextClick = ActionChains(driver).context_click(toContextClick) contextClick.perform() assert "ContextClicked" == toContextClick.get_attribute("value") def test_move_and_click(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" pages.load("javascriptPage.html") toClick = driver.find_element(By.ID, "clickField") click = ActionChains(driver).move_to_element(toClick).click() click.perform() assert "Clicked" == toClick.get_attribute("value") def test_cannot_move_to_anull_locator(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" pages.load("javascriptPage.html") with pytest.raises(AttributeError): move = ActionChains(driver).move_to_element(None) move.perform() @pytest.mark.xfail_safari def test_clicking_on_form_elements(driver, pages): """Copied from org.openqa.selenium.interactions.CombinedInputActionsTest.""" pages.load("formSelectionPage.html") options = driver.find_elements(By.TAG_NAME, "option") selectThreeOptions = ( ActionChains(driver).click(options[1]).key_down(Keys.SHIFT).click(options[3]).key_up(Keys.SHIFT) ) selectThreeOptions.perform() showButton = driver.find_element(By.NAME, "showselected") showButton.click() resultElement = driver.find_element(By.ID, "result") assert "roquefort parmigiano cheddar" == resultElement.text @pytest.mark.xfail_firefox @pytest.mark.xfail_safari def test_selecting_multiple_items(driver, pages): """Copied from org.openqa.selenium.interactions.CombinedInputActionsTest.""" pages.load("selectableItems.html") reportingElement = driver.find_element(By.ID, "infodiv") assert "no info" == reportingElement.text listItems = driver.find_elements(By.TAG_NAME, "li") selectThreeItems = ( ActionChains(driver) .key_down(Keys.CONTROL) .click(listItems[1]) .click(listItems[3]) .click(listItems[5]) .key_up(Keys.CONTROL) ) selectThreeItems.perform() assert "#item2 #item4 #item6" == reportingElement.text # Now click on another element, make sure that's the only one selected. actionsBuilder = ActionChains(driver) actionsBuilder.click(listItems[6]).perform() assert "#item7" == reportingElement.text @pytest.mark.xfail_safari def test_sending_keys_to_active_element_with_modifier(driver, pages): pages.load("formPage.html") e = driver.find_element(By.ID, "working") e.click() ActionChains(driver).key_down(Keys.SHIFT).send_keys("abc").key_up(Keys.SHIFT).perform() assert "ABC" == e.get_attribute("value") def test_sending_keys_to_element(driver, pages): pages.load("formPage.html") e = driver.find_element(By.ID, "working") ActionChains(driver).send_keys_to_element(e, "abc").perform() assert "abc" == e.get_attribute("value") def test_can_send_keys_between_clicks(driver, pages): """ For W3C, ensures that the correct number of pauses are given to the other input device. """ pages.load("javascriptPage.html") keyup = driver.find_element(By.ID, "keyUp") keydown = driver.find_element(By.ID, "keyDown") ActionChains(driver).click(keyup).send_keys("foobar").click(keydown).perform() assert "foobar" == keyup.get_attribute("value") def test_can_reset_interactions(driver): actions = ActionChains(driver) actions.click() actions.key_down("A") assert all(len(device.actions) > 0 for device in actions.w3c_actions.devices if device.type != interaction.WHEEL) actions.reset_actions() assert all(len(device.actions) == 0 for device in actions.w3c_actions.devices) def test_can_pause(driver, pages): from time import time pages.load("javascriptPage.html") pause_time = 2 toClick = driver.find_element(By.ID, "clickField") toDoubleClick = driver.find_element(By.ID, "doubleClickField") pause = ActionChains(driver).click(toClick).pause(pause_time).click(toDoubleClick) start = time() pause.perform() end = time() assert pause_time < end - start assert "Clicked" == toClick.get_attribute("value") assert "Clicked" == toDoubleClick.get_attribute("value") @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_scroll_to_element(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html") iframe = driver.find_element(By.TAG_NAME, "iframe") assert not _in_viewport(driver, iframe) ActionChains(driver).scroll_to_element(iframe).perform() assert _in_viewport(driver, iframe) @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_scroll_from_element_by_amount(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html") iframe = driver.find_element(By.TAG_NAME, "iframe") scroll_origin = ScrollOrigin.from_element(iframe) ActionChains(driver).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform() driver.switch_to.frame(iframe) checkbox = driver.find_element(By.NAME, "scroll_checkbox") assert _in_viewport(driver, checkbox) @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_scroll_from_element_with_offset_by_amount(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html") footer = driver.find_element(By.TAG_NAME, "footer") scroll_origin = ScrollOrigin.from_element(footer, 0, -50) ActionChains(driver).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform() iframe = driver.find_element(By.TAG_NAME, "iframe") driver.switch_to.frame(iframe) checkbox = driver.find_element(By.NAME, "scroll_checkbox") assert _in_viewport(driver, checkbox) def test_errors_when_element_offset_not_in_viewport(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html") footer = driver.find_element(By.TAG_NAME, "footer") scroll_origin = ScrollOrigin.from_element(footer, 0, 50) with pytest.raises(MoveTargetOutOfBoundsException): ActionChains(driver).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform() @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_scroll_from_viewport_by_amount(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html") footer = driver.find_element(By.TAG_NAME, "footer") delta_y = footer.rect["y"] ActionChains(driver).scroll_by_amount(0, delta_y).pause(0.2).perform() assert _in_viewport(driver, footer) def test_can_scroll_from_viewport_with_offset_by_amount(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame.html") scroll_origin = ScrollOrigin.from_viewport(10, 10) ActionChains(driver).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform() iframe = driver.find_element(By.TAG_NAME, "iframe") driver.switch_to.frame(iframe) checkbox = driver.find_element(By.NAME, "scroll_checkbox") assert _in_viewport(driver, checkbox) def test_errors_when_origin_offset_not_in_viewport(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame.html") scroll_origin = ScrollOrigin.from_viewport(-10, -10) with pytest.raises(MoveTargetOutOfBoundsException): ActionChains(driver).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform() def _get_events(driver): """Return list of key events recorded in the test_keys_page fixture.""" events = driver.execute_script("return allEvents.events;") or [] # `key` values in `allEvents` may be escaped (see `escapeSurrogateHalf` in # test_keys_wdspec.html), so this converts them back into unicode literals. for e in events: # example: turn "U+d83d" (6 chars) into u"\ud83d" (1 char) if "key" in e and e["key"].startswith("U+"): key = e["key"] hex_suffix = key[key.index("+") + 1 :] e["key"] = chr(int(hex_suffix, 16)) # WebKit sets code as 'Unidentified' for unidentified key codes, but # tests expect ''. if "code" in e and e["code"] == "Unidentified": e["code"] = "" return events def _in_viewport(driver, element): script = ( "for(var e=arguments[0],f=e.offsetTop,t=e.offsetLeft,o=e.offsetWidth,n=e.offsetHeight;\n" "e.offsetParent;)f+=(e=e.offsetParent).offsetTop,t+=e.offsetLeft;\n" "return f\n" "window.pageYOffset&&t+o>window.pageXOffset" ) return driver.execute_script(script, element) selenium-selenium-4.23.0/test/selenium/webdriver/common/position_and_size_tests.py0000664000175000017500000001103514646203155030525 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.by import By def test_should_be_able_to_determine_the_location_of_an_element(driver, pages): pages.load("xhtmlTest.html") location = driver.find_element(By.ID, "username").location_once_scrolled_into_view assert location["x"] > 0 assert location["y"] > 0 @pytest.mark.parametrize( "page", ( "coordinates_tests/simple_page.html", "coordinates_tests/page_with_empty_element.html", "coordinates_tests/page_with_transparent_element.html", "coordinates_tests/page_with_hidden_element.html", ), ids=("basic", "empty", "transparent", "hidden"), ) @pytest.mark.xfail_safari def test_should_get_coordinates_of_an_element(page, driver, pages): pages.load(page) element = driver.find_element(By.ID, "box") _check_location(element.location_once_scrolled_into_view, x=10, y=10) _check_location(element.location, x=10, y=10) @pytest.mark.xfail_safari def test_should_get_coordinates_of_an_invisible_element(driver, pages): pages.load("coordinates_tests/page_with_invisible_element.html") element = driver.find_element(By.ID, "box") _check_location(element.location_once_scrolled_into_view, x=0, y=0) _check_location(element.location, x=0, y=0) def test_should_scroll_page_and_get_coordinates_of_an_element_that_is_out_of_view_port(driver, pages): pages.load("coordinates_tests/page_with_element_out_of_view.html") element = driver.find_element(By.ID, "box") windowHeight = driver.get_window_size()["height"] _check_location(element.location_once_scrolled_into_view, x=10) assert 0 <= element.location_once_scrolled_into_view["y"] <= (windowHeight - 100) _check_location(element.location, x=10, y=5010) @pytest.mark.xfail_chrome @pytest.mark.xfail_edge @pytest.mark.xfail_firefox @pytest.mark.xfail_remote @pytest.mark.xfail_safari def test_should_get_coordinates_of_an_element_in_aframe(driver, pages): pages.load("coordinates_tests/element_in_frame.html") driver.switch_to.frame(driver.find_element(By.NAME, "ifr")) element = driver.find_element(By.ID, "box") _check_location(element.location_once_scrolled_into_view, x=25, y=25) _check_location(element.location, x=10, y=10) @pytest.mark.xfail_chrome @pytest.mark.xfail_edge @pytest.mark.xfail_firefox @pytest.mark.xfail_remote @pytest.mark.xfail_safari def test_should_get_coordinates_of_an_element_in_anested_frame(driver, pages): pages.load("coordinates_tests/element_in_nested_frame.html") driver.switch_to.frame(driver.find_element(By.NAME, "ifr")) driver.switch_to.frame(driver.find_element(By.NAME, "ifr")) element = driver.find_element(By.ID, "box") _check_location(element.location_once_scrolled_into_view, x=40, y=40) _check_location(element.location, x=10, y=10) def test_should_get_coordinates_of_an_element_with_fixed_position(driver, pages): pages.load("coordinates_tests/page_with_fixed_element.html") element = driver.find_element(By.ID, "fixed") _check_location(element.location_once_scrolled_into_view, y=0) _check_location(element.location, y=0) driver.find_element(By.ID, "bottom").click() _check_location(element.location_once_scrolled_into_view, y=0) assert element.location["y"] > 0 def test_should_correctly_identify_that_an_element_has_width_and_height(driver, pages): pages.load("xhtmlTest.html") shrinko = driver.find_element(By.ID, "linkId") size = shrinko.size assert size["width"] > 0 assert size["height"] > 0 def _check_location(location, **kwargs): try: # python 2.x expected = kwargs.viewitems() actual = location.viewitems() except AttributeError: # python 3.x expected = kwargs.items() actual = location.items() assert expected <= actual selenium-selenium-4.23.0/test/selenium/webdriver/common/script_pinning_tests.py0000664000175000017500000000512314646203155030034 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import re import pytest from selenium.common.exceptions import JavascriptException from selenium.webdriver.remote.script_key import ScriptKey def test_should_allow_script_pinning(driver, pages): pages.load("simpleTest.html") driver.pinned_scripts = {} script_key = driver.pin_script("return 'i like cheese';") result = driver.execute_script(script_key) assert result == "i like cheese" def test_should_allow_pinned_scripts_to_take_arguments(driver, pages): pages.load("simpleTest.html") driver.pinned_scripts = {} hello = driver.pin_script("return arguments[0]") result = driver.execute_script(hello, "cheese") assert result == "cheese" def test_should_list_all_pinned_scripts(driver, pages): pages.load("simpleTest.html") driver.pinned_scripts = {} expected = [] expected.append(driver.pin_script("return arguments[0];").id) expected.append(driver.pin_script("return 'cheese';").id) expected.append(driver.pin_script("return 42;").id) result = driver.get_pinned_scripts() assert expected == result def test_should_allow_scripts_to_be_unpinned(driver, pages): pages.load("simpleTest.html") driver.pinned_scripts = {} cheese = driver.pin_script("return 'cheese';") driver.unpin(cheese) results = driver.get_pinned_scripts() assert cheese not in results def test_calling_unpinned_script_causes_error(driver, pages): pages.load("simpleTest.html") cheese = driver.pin_script("return 'brie';") driver.unpin(cheese) with pytest.raises(JavascriptException): driver.execute_script(cheese) def test_unpinning_non_existing_script_raises(driver, pages): pages.load("simpleTest.html") with pytest.raises(KeyError, match=re.escape(r"No script with key: ScriptKey(id=1) existed in {}")): driver.unpin(ScriptKey(1)) selenium-selenium-4.23.0/test/selenium/webdriver/common/driver_element_finding_tests.py0000664000175000017500000007071314646203155031517 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import InvalidSelectorException from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.common.by import By # By.id positive def test_should_be_able_to_find_asingle_element_by_id(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.ID, "linkId") assert element.get_attribute("id") == "linkId" def test_should_be_able_to_find_asingle_element_by_numeric_id(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.ID, "2") assert element.get_attribute("id") == "2" def test_should_be_able_to_find_an_element_with_css_escape(driver, pages): pages.load("idElements.html") element = driver.find_element(By.ID, "with.dots") assert element.get_attribute("id") == "with.dots" def test_should_be_able_to_find_multiple_elements_by_id(driver, pages): pages.load("nestedElements.html") elements = driver.find_elements(By.ID, "test_id") assert len(elements) == 2 def test_should_be_able_to_find_multiple_elements_by_numeric_id(driver, pages): pages.load("nestedElements.html") elements = driver.find_elements(By.ID, "2") assert len(elements) == 8 # By.id negative def test_should_not_be_able_to_locate_by_id_asingle_element_that_does_not_exist(driver, pages): pages.load("formPage.html") with pytest.raises(NoSuchElementException): driver.find_element(By.ID, "non_Existent_Button") def test_should_not_be_able_to_locate_by_id_multiple_elements_that_do_not_exist(driver, pages): pages.load("formPage.html") elements = driver.find_elements(By.ID, "non_Existent_Button") assert len(elements) == 0 def test_finding_asingle_element_by_empty_id_should_throw(driver, pages): pages.load("formPage.html") with pytest.raises(NoSuchElementException): driver.find_element(By.ID, "") def test_finding_multiple_elements_by_empty_id_should_return_empty_list(driver, pages): pages.load("formPage.html") elements = driver.find_elements(By.ID, "") assert len(elements) == 0 def test_finding_asingle_element_by_id_with_space_should_throw(driver, pages): pages.load("formPage.html") with pytest.raises(NoSuchElementException): driver.find_element(By.ID, "nonexistent button") def test_finding_multiple_elements_by_id_with_space_should_return_empty_list(driver, pages): pages.load("formPage.html") elements = driver.find_elements(By.ID, "nonexistent button") assert len(elements) == 0 def test_no_such_element_error(driver, pages): pages.load("formPage.html") msg = r"\/errors#no-such-element-exception" with pytest.raises(NoSuchElementException, match=msg): driver.find_element(By.ID, "non_Existent_Button") # By.name positive def test_should_be_able_to_find_asingle_element_by_name(driver, pages): pages.load("formPage.html") element = driver.find_element(By.NAME, "checky") assert element.get_attribute("value") == "furrfu" def test_should_be_able_to_find_multiple_elements_by_name(driver, pages): pages.load("nestedElements.html") elements = driver.find_elements(By.NAME, "checky") assert len(elements) > 1 def test_should_be_able_to_find_an_element_that_does_not_support_the_name_property(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "div1") assert element.get_attribute("name") == "div1" # By.name negative def test_should_not_be_able_to_locate_by_name_asingle_element_that_does_not_exist(driver, pages): pages.load("formPage.html") with pytest.raises(NoSuchElementException): driver.find_element(By.NAME, "non_Existent_Button") def test_should_not_be_able_to_locate_by_name_multiple_elements_that_do_not_exist(driver, pages): pages.load("formPage.html") elements = driver.find_elements(By.NAME, "non_Existent_Button") assert len(elements) == 0 def test_finding_asingle_element_by_empty_name_should_throw(driver, pages): pages.load("formPage.html") with pytest.raises(NoSuchElementException): driver.find_element(By.NAME, "") def test_finding_multiple_elements_by_empty_name_should_return_empty_list(driver, pages): pages.load("formPage.html") elements = driver.find_elements(By.NAME, "") assert len(elements) == 0 def test_finding_asingle_element_by_name_with_space_should_throw(driver, pages): pages.load("formPage.html") with pytest.raises(NoSuchElementException): driver.find_element(By.NAME, "nonexistent button") def test_finding_multiple_elements_by_name_with_space_should_return_empty_list(driver, pages): pages.load("formPage.html") elements = driver.find_elements(By.NAME, "nonexistent button") assert len(elements) == 0 # By.tag_Name positive def test_should_be_able_to_find_asingle_element_by_tag_name(driver, pages): pages.load("formPage.html") element = driver.find_element(By.TAG_NAME, "input") assert element.tag_name.lower() == "input" def test_should_be_able_to_find_multiple_elements_by_tag_name(driver, pages): pages.load("formPage.html") elements = driver.find_elements(By.TAG_NAME, "input") assert len(elements) > 1 # By.tag_Name negative def test_should_not_be_able_to_locate_by_tag_name_asingle_element_that_does_not_exist(driver, pages): pages.load("formPage.html") with pytest.raises(NoSuchElementException): driver.find_element(By.TAG_NAME, "non_Existent_Button") def test_should_not_be_able_to_locate_by_tag_name_multiple_elements_that_do_not_exist(driver, pages): pages.load("formPage.html") elements = driver.find_elements(By.TAG_NAME, "non_Existent_Button") assert len(elements) == 0 @pytest.mark.xfail_firefox(reason="https://github.com/mozilla/geckodriver/issues/2007") @pytest.mark.xfail_remote(reason="https://github.com/mozilla/geckodriver/issues/2007") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises NoSuchElementException") @pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") @pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") def test_finding_asingle_element_by_empty_tag_name_should_throw(driver, pages): pages.load("formPage.html") with pytest.raises(InvalidSelectorException): driver.find_element(By.TAG_NAME, "") @pytest.mark.xfail_firefox(reason="https://github.com/mozilla/geckodriver/issues/2007") @pytest.mark.xfail_remote(reason="https://github.com/mozilla/geckodriver/issues/2007") @pytest.mark.xfail_safari(reason="unlike chrome, safari returns an empty list") @pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") @pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") def test_finding_multiple_elements_by_empty_tag_name_should_throw(driver, pages): pages.load("formPage.html") with pytest.raises(InvalidSelectorException): driver.find_elements(By.TAG_NAME, "") def test_finding_asingle_element_by_tag_name_with_space_should_throw(driver, pages): pages.load("formPage.html") with pytest.raises(NoSuchElementException): driver.find_element(By.TAG_NAME, "nonexistent button") def test_finding_multiple_elements_by_tag_name_with_space_should_return_empty_list(driver, pages): pages.load("formPage.html") elements = driver.find_elements(By.TAG_NAME, "nonexistent button") assert len(elements) == 0 # By.class_Name positive def test_should_be_able_to_find_asingle_element_by_class(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.CLASS_NAME, "extraDiv") assert "Another div starts here." in element.text def test_should_be_able_to_find_multiple_elements_by_class_name(driver, pages): pages.load("xhtmlTest.html") elements = driver.find_elements(By.CLASS_NAME, "nameC") assert len(elements) > 1 def test_should_find_element_by_class_when_it_is_the_first_name_among_many(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.CLASS_NAME, "nameA") assert element.text == "An H2 title" def test_should_find_element_by_class_when_it_is_the_last_name_among_many(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.CLASS_NAME, "nameC") assert element.text == "An H2 title" def test_should_find_element_by_class_when_it_is_in_the_middle_among_many(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.CLASS_NAME, "nameBnoise") assert element.text == "An H2 title" def test_should_find_element_by_class_when_its_name_is_surrounded_by_whitespace(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.CLASS_NAME, "spaceAround") assert element.text == "Spaced out" def test_should_find_elements_by_class_when_its_name_is_surrounded_by_whitespace(driver, pages): pages.load("xhtmlTest.html") elements = driver.find_elements(By.CLASS_NAME, "spaceAround") assert len(elements) == 1 assert elements[0].text == "Spaced out" # By.class_Name negative def test_should_not_find_element_by_class_when_the_name_queried_is_shorter_than_candidate_name(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(NoSuchElementException): driver.find_element(By.CLASS_NAME, "name_B") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") @pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") @pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") def test_finding_asingle_element_by_empty_class_name_should_throw(driver, pages): pages.load("xhtmlTest.html") msg = r"\/errors#invalid-selector-exception" with pytest.raises(InvalidSelectorException, match=msg): driver.find_element(By.CLASS_NAME, "") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") @pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") @pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") def test_finding_multiple_elements_by_empty_class_name_should_throw(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(InvalidSelectorException): driver.find_elements(By.CLASS_NAME, "") def test_finding_asingle_element_by_compound_class_name_should_throw(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(NoSuchElementException): driver.find_element(By.CLASS_NAME, "a b") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") @pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") @pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") def test_finding_asingle_element_by_invalid_class_name_should_throw(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(InvalidSelectorException): driver.find_element(By.CLASS_NAME, "!@#$%^&*") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") @pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") @pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") def test_finding_multiple_elements_by_invalid_class_name_should_throw(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(InvalidSelectorException): driver.find_elements(By.CLASS_NAME, "!@#$%^&*") # By.xpath positive def test_should_be_able_to_find_asingle_element_by_xpath(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.XPATH, "//h1") assert element.text == "XHTML Might Be The Future" def test_should_be_able_to_find_multiple_elements_by_xpath(driver, pages): pages.load("xhtmlTest.html") elements = driver.find_elements(By.XPATH, "//div") assert len(elements) == 13 def test_should_be_able_to_find_many_elements_repeatedly_by_xpath(driver, pages): pages.load("xhtmlTest.html") xpath = "//node()[contains(@id,'id')]" assert len(driver.find_elements(By.XPATH, xpath)) == 3 xpath = "//node()[contains(@id,'nope')]" assert len(driver.find_elements(By.XPATH, xpath)) == 0 def test_should_be_able_to_identify_elements_by_class(driver, pages): pages.load("xhtmlTest.html") header = driver.find_element(By.XPATH, "//h1[@class='header']") assert header.text == "XHTML Might Be The Future" def test_should_be_able_to_find_an_element_by_xpath_with_multiple_attributes(driver, pages): pages.load("formPage.html") element = driver.find_element(By.XPATH, "//form[@name='optional']/input[@type='submit' and @value='Click!']") assert element.tag_name.lower() == "input" assert element.get_attribute("value") == "Click!" def test_finding_alink_by_xpath_should_locate_an_element_with_the_given_text(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.XPATH, "//a[text()='click me']") assert element.text == "click me" def test_finding_alink_by_xpath_using_contains_keyword_should_work(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.XPATH, "//a[contains(.,'hello world')]") assert "hello world" in element.text # @pytest.mark.xfail_chrome(raises=InvalidSelectorException) # @pytest.mark.xfail_edge(raises=InvalidSelectorException) # @pytest.mark.xfail_firefox(raises=InvalidSelectorException) # @pytest.mark.xfail_remote(raises=InvalidSelectorException) # @pytest.mark.xfail_safari(raises=NoSuchElementException) # @pytest.mark.xfail_webkitgtk(raises=InvalidSelectorException) # def test_Should_Be_Able_To_Find_Element_By_XPath_With_Namespace(driver, pages): # pages.load("svgPage.html") # element = driver.find_element(By.XPATH, "//svg:svg//svg:text") # assert element.text == "Test Chart" def test_should_be_able_to_find_element_by_xpath_in_xml_document(driver, pages): pages.load("simple.xml") element = driver.find_element(By.XPATH, "//foo") assert "baz" in element.text # By.xpath negative def test_should_throw_an_exception_when_there_is_no_link_to_click(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(NoSuchElementException): driver.find_element(By.XPATH, "//a[@id='Not here']") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") @pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") @pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") def test_should_throw_invalid_selector_exception_when_xpath_is_syntactically_invalid_in_driver_find_element( driver, pages ): pages.load("formPage.html") with pytest.raises(InvalidSelectorException): driver.find_element(By.XPATH, "this][isnot][valid") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") @pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") @pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") def test_should_throw_invalid_selector_exception_when_xpath_is_syntactically_invalid_in_driver_find_elements( driver, pages ): pages.load("formPage.html") with pytest.raises(InvalidSelectorException): driver.find_elements(By.XPATH, "this][isnot][valid") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") @pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") @pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") def test_should_throw_invalid_selector_exception_when_xpath_is_syntactically_invalid_in_element_find_element( driver, pages ): pages.load("formPage.html") body = driver.find_element(By.TAG_NAME, "body") with pytest.raises(InvalidSelectorException): body.find_element(By.XPATH, "this][isnot][valid") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") @pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") @pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") def test_should_throw_invalid_selector_exception_when_xpath_is_syntactically_invalid_in_element_find_elements( driver, pages ): pages.load("formPage.html") body = driver.find_element(By.TAG_NAME, "body") with pytest.raises(InvalidSelectorException): body.find_elements(By.XPATH, "this][isnot][valid") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") @pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") @pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") def test_should_throw_invalid_selector_exception_when_xpath_returns_wrong_type_in_driver_find_element(driver, pages): pages.load("formPage.html") with pytest.raises(InvalidSelectorException): driver.find_element(By.XPATH, "count(//input)") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") @pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") @pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") def test_should_throw_invalid_selector_exception_when_xpath_returns_wrong_type_in_driver_find_elements(driver, pages): pages.load("formPage.html") with pytest.raises(InvalidSelectorException): driver.find_elements(By.XPATH, "count(//input)") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") @pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") @pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") def test_should_throw_invalid_selector_exception_when_xpath_returns_wrong_type_in_element_find_element(driver, pages): pages.load("formPage.html") body = driver.find_element(By.TAG_NAME, "body") with pytest.raises(InvalidSelectorException): body.find_element(By.XPATH, "count(//input)") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") @pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") @pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") def test_should_throw_invalid_selector_exception_when_xpath_returns_wrong_type_in_element_find_elements(driver, pages): pages.load("formPage.html") body = driver.find_element(By.TAG_NAME, "body") with pytest.raises(InvalidSelectorException): body.find_elements(By.XPATH, "count(//input)") # By.css_Selector positive def test_should_be_able_to_find_asingle_element_by_css_selector(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.CSS_SELECTOR, "div.content") assert element.tag_name.lower() == "div" assert element.get_attribute("class") == "content" def test_should_be_able_to_find_multiple_elements_by_css_selector(driver, pages): pages.load("xhtmlTest.html") elements = driver.find_elements(By.CSS_SELECTOR, "p") assert len(elements) > 1 def test_should_be_able_to_find_asingle_element_by_compound_css_selector(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.CSS_SELECTOR, "div.extraDiv, div.content") assert element.tag_name.lower() == "div" assert element.get_attribute("class") == "content" def test_should_be_able_to_find_multiple_elements_by_compound_css_selector(driver, pages): pages.load("xhtmlTest.html") elements = driver.find_elements(By.CSS_SELECTOR, "div.extraDiv, div.content") assert len(elements) > 1 assert elements[0].get_attribute("class") == "content" assert elements[1].get_attribute("class") == "extraDiv" def test_should_be_able_to_find_an_element_by_boolean_attribute_using_css_selector(driver, pages): pages.load("locators_tests/boolean_attribute_selected.html") element = driver.find_element(By.CSS_SELECTOR, "option[selected='selected']") assert element.get_attribute("value") == "two" def test_should_be_able_to_find_an_element_by_boolean_attribute_using_short_css_selector(driver, pages): pages.load("locators_tests/boolean_attribute_selected.html") element = driver.find_element(By.CSS_SELECTOR, "option[selected]") assert element.get_attribute("value") == "two" def test_should_be_able_to_find_an_element_by_boolean_attribute_using_short_css_selector_on_html_4_page(driver, pages): pages.load("locators_tests/boolean_attribute_selected_html4.html") element = driver.find_element(By.CSS_SELECTOR, "option[selected]") assert element.get_attribute("value") == "two" # By.css_Selector negative def test_should_not_find_element_by_css_selector_when_there_is_no_such_element(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(NoSuchElementException): driver.find_element(By.CSS_SELECTOR, ".there-is-no-such-class") def test_should_not_find_elements_by_css_selector_when_there_is_no_such_element(driver, pages): pages.load("xhtmlTest.html") elements = driver.find_elements(By.CSS_SELECTOR, ".there-is-no-such-class") assert len(elements) == 0 @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") @pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") @pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") def test_finding_asingle_element_by_empty_css_selector_should_throw(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(InvalidSelectorException): driver.find_element(By.CSS_SELECTOR, "") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") @pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") @pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") def test_finding_multiple_elements_by_empty_css_selector_should_throw(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(InvalidSelectorException): driver.find_elements(By.CSS_SELECTOR, "") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") @pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") @pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") def test_finding_asingle_element_by_invalid_css_selector_should_throw(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(InvalidSelectorException): driver.find_element(By.CSS_SELECTOR, "//a/b/c[@id='1']") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") @pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") @pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") def test_finding_multiple_elements_by_invalid_css_selector_should_throw(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(InvalidSelectorException): driver.find_elements(By.CSS_SELECTOR, "//a/b/c[@id='1']") # By.link_Text positive def test_should_be_able_to_find_alink_by_text(driver, pages): pages.load("xhtmlTest.html") link = driver.find_element(By.LINK_TEXT, "click me") assert link.text == "click me" def test_should_be_able_to_find_multiple_links_by_text(driver, pages): pages.load("xhtmlTest.html") elements = driver.find_elements(By.LINK_TEXT, "click me") assert len(elements) == 2 def test_should_find_element_by_link_text_containing_equals_sign(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.LINK_TEXT, "Link=equalssign") assert element.get_attribute("id") == "linkWithEqualsSign" def test_should_find_multiple_elements_by_link_text_containing_equals_sign(driver, pages): pages.load("xhtmlTest.html") elements = driver.find_elements(By.LINK_TEXT, "Link=equalssign") assert 1 == len(elements) assert elements[0].get_attribute("id") == "linkWithEqualsSign" def test_finds_by_link_text_on_xhtml_page(driver, pages): pages.load("actualXhtmlPage.xhtml") link_Text = "Foo" element = driver.find_element(By.LINK_TEXT, link_Text) assert element.text == link_Text def test_link_with_formatting_tags(driver, pages): pages.load("simpleTest.html") elem = driver.find_element(By.ID, "links") res = elem.find_element(By.PARTIAL_LINK_TEXT, "link with formatting tags") assert res.text == "link with formatting tags" @pytest.mark.xfail_safari def test_driver_can_get_link_by_link_test_ignoring_trailing_whitespace(driver, pages): pages.load("simpleTest.html") link = driver.find_element(By.LINK_TEXT, "link with trailing space") assert link.get_attribute("id") == "linkWithTrailingSpace" assert link.text == "link with trailing space" # By.link_Text negative def test_should_not_be_able_to_locate_by_link_text_asingle_element_that_does_not_exist(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(NoSuchElementException): driver.find_element(By.LINK_TEXT, "Not here either") def test_should_not_be_able_to_locate_by_link_text_multiple_elements_that_do_not_exist(driver, pages): pages.load("xhtmlTest.html") elements = driver.find_elements(By.LINK_TEXT, "Not here either") assert len(elements) == 0 # By.partial_Link_Text positive def test_should_be_able_to_find_multiple_elements_by_partial_link_text(driver, pages): pages.load("xhtmlTest.html") elements = driver.find_elements(By.PARTIAL_LINK_TEXT, "ick me") assert len(elements) == 2 def test_should_be_able_to_find_asingle_element_by_partial_link_text(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.PARTIAL_LINK_TEXT, "anon") assert "anon" in element.text def test_should_find_element_by_partial_link_text_containing_equals_sign(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.PARTIAL_LINK_TEXT, "Link=") assert element.get_attribute("id") == "linkWithEqualsSign" def test_should_find_multiple_elements_by_partial_link_text_containing_equals_sign(driver, pages): pages.load("xhtmlTest.html") elements = driver.find_elements(By.PARTIAL_LINK_TEXT, "Link=") assert len(elements) == 1 assert elements[0].get_attribute("id") == "linkWithEqualsSign" # Misc tests def test_driver_should_be_able_to_find_elements_after_loading_more_than_one_page_at_atime(driver, pages): pages.load("formPage.html") pages.load("xhtmlTest.html") link = driver.find_element(By.LINK_TEXT, "click me") assert link.text == "click me" # You don't want to ask why this is here def test_when_finding_by_name_should_not_return_by_id(driver, pages): pages.load("formPage.html") element = driver.find_element(By.NAME, "id-name1") assert element.get_attribute("value") == "name" element = driver.find_element(By.ID, "id-name1") assert element.get_attribute("value") == "id" element = driver.find_element(By.NAME, "id-name2") assert element.get_attribute("value") == "name" element = driver.find_element(By.ID, "id-name2") assert element.get_attribute("value") == "id" def test_should_be_able_to_find_ahidden_elements_by_name(driver, pages): pages.load("formPage.html") element = driver.find_element(By.NAME, "hidden") assert element.get_attribute("name") == "hidden" def test_should_not_be_able_to_find_an_element_on_a_blank_page(driver, pages): driver.get("about:blank") with pytest.raises(NoSuchElementException): driver.find_element(By.TAG_NAME, "a") selenium-selenium-4.23.0/test/selenium/webdriver/common/page_loader.py0000664000175000017500000000257414646203155026035 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """This module contains some decorators that can be used to support the page models. For example for an action that needs a page to be fully loaded, the @require_loaded decorator will make sure the page is loaded before the call is invoked. This pattern is also useful for waiting for certain asynchronous events to happen before executing certain actions.""" def require_loaded(func): def load_page(page, *params, **kwds): if not page.is_loaded(): page.load() assert page.is_loaded(), "page should be loaded by now" return func(page, *params, **kwds) return load_page selenium-selenium-4.23.0/test/selenium/webdriver/common/example2.py0000664000175000017500000000223414646203155025301 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from google_one_box import GoogleOneBox def test_search(driver): """This example shows how to use the page object pattern. For more information about this pattern, see: https://github.com/SeleniumHQ/selenium/wiki/PageObjects""" google = GoogleOneBox(driver, "http://www.google.com") res = google.search_for("cheese") assert res.link_contains_match_for("Wikipedia") selenium-selenium-4.23.0/test/selenium/webdriver/common/print_pdf_tests.py0000664000175000017500000000456114646203155027000 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.print_page_options import PrintOptions START_INDEX = 0 END_INDEX = 5 PDF_MAGIC_NUMBER = "JVBER" @pytest.mark.xfail_safari(reason="no endpoint for print in safari") def test_pdf_with_2_pages(driver, pages): print_options = PrintOptions() print_options.page_ranges = ["1-2"] pages.load("printPage.html") base64code = driver.print_page(print_options) assert base64code[START_INDEX:END_INDEX] == PDF_MAGIC_NUMBER @pytest.mark.xfail_safari(reason="no endpoint for print in safari") def test_pdf_with_all_pages(driver, pages): pages.load("printPage.html") base64code = driver.print_page() assert base64code[START_INDEX:END_INDEX] == PDF_MAGIC_NUMBER @pytest.mark.xfail_safari(reason="no endpoint for print in safari") def test_valid_params(driver, pages): print_options = PrintOptions() print_options.page_ranges = ["1-2"] print_options.orientation = "landscape" print_options.width = 30 pages.load("printPage.html") base64code = driver.print_page(print_options) assert base64code[START_INDEX:END_INDEX] == PDF_MAGIC_NUMBER @pytest.mark.xfail_safari(reason="no endpoint for print in safari") def test_session_id_is_not_preserved_after_page_is_printed(driver, pages): print_options = PrintOptions() print_options.margin_bottom = print_options.margin_top = print_options.margin_left = print_options.margin_right = 0 assert "sessionId" not in print_options.to_dict() pages.load("printPage.html") driver.print_page(print_options=print_options) assert "sessionId" not in print_options.to_dict() selenium-selenium-4.23.0/test/selenium/webdriver/common/element_attribute_tests.py0000664000175000017500000002607214646203155030530 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By def test_should_return_null_when_getting_the_value_of_an_attribute_that_is_not_listed(driver, pages): pages.load("simpleTest.html") head = driver.find_element(By.XPATH, "/html") attribute = head.get_attribute("cheese") assert attribute is None def test_should_return_null_when_getting_src_attribute_of_invalid_img_tag(driver, pages): pages.load("simpleTest.html") img = driver.find_element(By.ID, "invalidImgTag") img_attr = img.get_attribute("src") assert img_attr is None def test_should_return_an_absolute_url_when_getting_src_attribute_of_avalid_img_tag(driver, pages): pages.load("simpleTest.html") img = driver.find_element(By.ID, "validImgTag") img_attr = img.get_attribute("src") assert "icon.gif" in img_attr def test_should_return_an_absolute_url_when_getting_href_attribute_of_avalid_anchor_tag(driver, pages): pages.load("simpleTest.html") img = driver.find_element(By.ID, "validAnchorTag") img_attr = img.get_attribute("href") assert "icon.gif" in img_attr def test_should_return_empty_attribute_values_when_present_and_the_value_is_actually_empty(driver, pages): pages.load("simpleTest.html") body = driver.find_element(By.XPATH, "//body") assert "" == body.get_attribute("style") def test_should_return_the_value_of_the_disabled_attribute_as_false_if_not_set(driver, pages): pages.load("formPage.html") inputElement = driver.find_element(By.XPATH, "//input[@id='working']") assert inputElement.get_attribute("disabled") is None assert inputElement.is_enabled() pElement = driver.find_element(By.ID, "peas") assert pElement.get_attribute("disabled") is None assert pElement.is_enabled() def test_should_return_the_value_of_the_index_attribute_even_if_it_is_missing(driver, pages): pages.load("formPage.html") multiSelect = driver.find_element(By.ID, "multi") options = multiSelect.find_elements(By.TAG_NAME, "option") assert "1" == options[1].get_attribute("index") def test_should_indicate_the_elements_that_are_disabled_are_not_is_enabled(driver, pages): pages.load("formPage.html") inputElement = driver.find_element(By.XPATH, "//input[@id='notWorking']") assert not inputElement.is_enabled() inputElement = driver.find_element(By.XPATH, "//input[@id='working']") assert inputElement.is_enabled() def test_elements_should_be_disabled_if_they_are_disabled_using_random_disabled_strings(driver, pages): pages.load("formPage.html") disabledTextElement1 = driver.find_element(By.ID, "disabledTextElement1") assert not disabledTextElement1.is_enabled() disabledTextElement2 = driver.find_element(By.ID, "disabledTextElement2") assert not disabledTextElement2.is_enabled() disabledSubmitElement = driver.find_element(By.ID, "disabledSubmitElement") assert not disabledSubmitElement.is_enabled() def test_should_indicate_when_atext_area_is_disabled(driver, pages): pages.load("formPage.html") textArea = driver.find_element(By.XPATH, "//textarea[@id='notWorkingArea']") assert not textArea.is_enabled() @pytest.mark.xfail_safari def test_should_throw_exception_if_sending_keys_to_element_disabled_using_random_disabled_strings(driver, pages): pages.load("formPage.html") disabledTextElement1 = driver.find_element(By.ID, "disabledTextElement1") with pytest.raises(WebDriverException): disabledTextElement1.send_keys("foo") assert "" == disabledTextElement1.text disabledTextElement2 = driver.find_element(By.ID, "disabledTextElement2") with pytest.raises(WebDriverException): disabledTextElement2.send_keys("bar") assert "" == disabledTextElement2.text def test_should_indicate_when_aselect_is_disabled(driver, pages): pages.load("formPage.html") enabled = driver.find_element(By.NAME, "selectomatic") disabled = driver.find_element(By.NAME, "no-select") assert enabled.is_enabled() assert not disabled.is_enabled() def test_should_return_the_value_of_checked_for_acheckbox_even_if_it_lacks_that_attribute(driver, pages): pages.load("formPage.html") checkbox = driver.find_element(By.XPATH, "//input[@id='checky']") assert checkbox.get_attribute("checked") is None checkbox.click() assert "true" == checkbox.get_attribute("checked") def test_should_return_the_value_of_selected_for_radio_buttons_even_if_they_lack_that_attribute(driver, pages): pages.load("formPage.html") neverSelected = driver.find_element(By.ID, "cheese") initiallyNotSelected = driver.find_element(By.ID, "peas") initiallySelected = driver.find_element(By.ID, "cheese_and_peas") assert neverSelected.get_attribute("checked") is None assert initiallyNotSelected.get_attribute("checked") is None assert "true" == initiallySelected.get_attribute("checked") initiallyNotSelected.click() assert neverSelected.get_attribute("selected") is None assert "true" == initiallyNotSelected.get_attribute("checked") assert initiallySelected.get_attribute("checked") is None def test_should_return_the_value_of_selected_for_options_in_selects_even_if_they_lack_that_attribute(driver, pages): pages.load("formPage.html") selectBox = driver.find_element(By.XPATH, "//select[@name='selectomatic']") options = selectBox.find_elements(By.TAG_NAME, "option") one = options[0] two = options[1] assert one.is_selected() assert not two.is_selected() assert "true" == one.get_attribute("selected") assert two.get_attribute("selected") is None def test_should_return_value_of_class_attribute_of_an_element(driver, pages): pages.load("xhtmlTest.html") heading = driver.find_element(By.XPATH, "//h1") classname = heading.get_attribute("class") assert "header" == classname # Disabled due to issues with Frames # def test_should_return_value_of_class_attribute_of_an_element_after_switching_iframe(driver, pages): # pages.load("iframes.html") # driver.switch_to.frame("iframe1") # # wallace = driver.find_element(By.XPATH, "//div[@id='wallace']") # classname = wallace.get_attribute("class") # assert "gromit" == classname def test_should_return_the_contents_of_atext_area_as_its_value(driver, pages): pages.load("formPage.html") value = driver.find_element(By.ID, "withText").get_attribute("value") assert "Example text" == value def test_should_return_the_contents_of_atext_area_as_its_value_when_set_to_non_norminal_true(driver, pages): pages.load("formPage.html") e = driver.find_element(By.ID, "withText") driver.execute_script("arguments[0].value = 'tRuE'", e) value = e.get_attribute("value") assert "tRuE" == value def test_should_treat_readonly_as_avalue(driver, pages): pages.load("formPage.html") element = driver.find_element(By.NAME, "readonly") readOnlyAttribute = element.get_attribute("readonly") textInput = driver.find_element(By.NAME, "x") notReadOnly = textInput.get_attribute("readonly") assert readOnlyAttribute != notReadOnly def test_should_get_numeric_attribute(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "withText") assert "5" == element.get_attribute("rows") def test_can_return_atext_approximation_of_the_style_attribute(driver, pages): pages.load("javascriptPage.html") style = driver.find_element(By.ID, "red-item").get_attribute("style") assert "background-color" in style.lower() def test_should_correctly_report_value_of_colspan(driver, pages): pages.load("tables.html") th1 = driver.find_element(By.ID, "th1") td2 = driver.find_element(By.ID, "td2") assert "th1" == th1.get_attribute("id") assert "3" == th1.get_attribute("colspan") assert "td2" == td2.get_attribute("id") assert "2" == td2.get_attribute("colspan") def test_can_retrieve_the_current_value_of_atext_form_field_text_input(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "working") assert "" == element.get_attribute("value") element.send_keys("hello world") assert "hello world" == element.get_attribute("value") def test_can_retrieve_the_current_value_of_atext_form_field_email_input(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "email") assert "" == element.get_attribute("value") element.send_keys("hello@example.com") assert "hello@example.com" == element.get_attribute("value") def test_can_retrieve_the_current_value_of_atext_form_field_text_area(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "emptyTextArea") assert "" == element.get_attribute("value") element.send_keys("hello world") assert "hello world" == element.get_attribute("value") def test_should_return_null_for_non_present_boolean_attributes(driver, pages): pages.load("booleanAttributes.html") element1 = driver.find_element(By.ID, "working") assert element1.get_attribute("required") is None @pytest.mark.xfail_ie def test_should_return_true_for_present_boolean_attributes(driver, pages): pages.load("booleanAttributes.html") element1 = driver.find_element(By.ID, "emailRequired") assert "true" == element1.get_attribute("required") element2 = driver.find_element(By.ID, "emptyTextAreaRequired") assert "true" == element2.get_attribute("required") element3 = driver.find_element(By.ID, "inputRequired") assert "true" == element3.get_attribute("required") element4 = driver.find_element(By.ID, "textAreaRequired") assert "true" == element4.get_attribute("required") @pytest.mark.xfail_chrome @pytest.mark.xfail_edge @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_should_get_unicode_chars_from_attribute(driver, pages): pages.load("formPage.html") title = driver.find_element(By.ID, "vsearchGadget").get_attribute("title") assert "Hvad s\xf8ger du?" == title @pytest.mark.xfail_chrome @pytest.mark.xfail_edge @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_should_get_values_and_not_miss_items(driver, pages): pages.load("attributes.html") expected = "4b273a33fbbd29013nN93dy4F1A~" result = driver.find_element(By.CSS_SELECTOR, "li").get_attribute("value") assert expected == result selenium-selenium-4.23.0/test/selenium/webdriver/common/w3c_interaction_tests.py0000664000175000017500000003173114646203155030105 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.actions import interaction from selenium.webdriver.common.actions.action_builder import ActionBuilder from selenium.webdriver.common.actions.pointer_input import PointerInput from selenium.webdriver.common.actions.wheel_input import WheelInput from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.ui import WebDriverWait def test_should_be_able_to_get_pointer_and_keyboard_inputs(driver, pages): actions = ActionBuilder(driver) pointers = actions.pointer_inputs keyboards = actions.key_inputs assert pointers is not None assert keyboards is not None @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_sending_keys_to_active_element_with_modifier(driver, pages): pages.load("formPage.html") e = driver.find_element(By.ID, "working") e.click() actions = ActionBuilder(driver) key_action = actions.key_action key_action.key_down(Keys.SHIFT).send_keys("abc").key_up(Keys.SHIFT) actions.perform() assert "ABC" == e.get_attribute("value") @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_create_pause_action_on_keyboard(driver, pages): # If we don't get an error and takes less than 3 seconds to run, we are good import datetime start = datetime.datetime.now() actions1 = ActionBuilder(driver) key_actions = actions1.key_action key_actions.pause(1) actions1.perform() finish = datetime.datetime.now() assert (finish - start).seconds <= 3 # Add a filler step actions2 = ActionBuilder(driver) key_action = actions2.key_action key_action.pause() actions2.perform() def test_can_create_pause_action_on_pointer(driver, pages): # If we don't get an error and takes less than 3 seconds to run, we are good import datetime start = datetime.datetime.now() actions1 = ActionBuilder(driver) key_actions = actions1.pointer_action key_actions.pause(1) actions1.perform() finish = datetime.datetime.now() assert (finish - start).seconds <= 3 # Add a filler step actions2 = ActionBuilder(driver) key_action = actions2.pointer_action key_action.pause() actions2.perform() def test_can_clear_actions(driver, pages): actions = ActionBuilder(driver) actions.clear_actions() def test_move_and_click(driver, pages): pages.load("javascriptPage.html") toClick = driver.find_element(By.ID, "clickField") actions = ActionBuilder(driver) pointer = actions.pointer_action pointer.move_to(toClick).click() actions.perform() assert "Clicked" == toClick.get_attribute("value") def test_drag_and_drop(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" element_available_timeout = 15 wait = WebDriverWait(driver, element_available_timeout) pages.load("droppableItems.html") wait.until(lambda dr: _is_element_available(driver, "draggable")) if not _is_element_available(driver, "draggable"): raise AssertionError("Could not find draggable element after 15 seconds.") toDrag = driver.find_element(By.ID, "draggable") dropInto = driver.find_element(By.ID, "droppable") actions = ActionBuilder(driver) pointer = actions.pointer_action pointer.click_and_hold(toDrag).move_to(dropInto).release() actions.perform() dropInto = driver.find_element(By.ID, "droppable") text = dropInto.find_element(By.TAG_NAME, "p").text assert "Dropped!" == text def test_context_click(driver, pages): pages.load("javascriptPage.html") toContextClick = driver.find_element(By.ID, "doubleClickField") actions = ActionBuilder(driver) pointer = actions.pointer_action pointer.context_click(toContextClick) actions.perform() assert "ContextClicked" == toContextClick.get_attribute("value") @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote(reason="Fails on Travis") @pytest.mark.xfail_chrome(reason="Fails on Travis") def test_double_click(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" pages.load("javascriptPage.html") toDoubleClick = driver.find_element(By.ID, "doubleClickField") actions = ActionBuilder(driver) pointer = actions.pointer_action pointer.double_click(toDoubleClick) actions.perform() assert "DoubleClicked" == toDoubleClick.get_attribute("value") def test_dragging_element_with_mouse_moves_it_to_another_list(driver, pages): _perform_drag_and_drop_with_mouse(driver, pages) dragInto = driver.find_element(By.ID, "sortable1") assert 6 == len(dragInto.find_elements(By.TAG_NAME, "li")) def test_dragging_element_with_mouse_fires_events(driver, pages): _perform_drag_and_drop_with_mouse(driver, pages) dragReporter = driver.find_element(By.ID, "dragging_reports") assert "Nothing happened. DragOut DropIn RightItem 3" == dragReporter.text @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_pen_pointer_properties(driver, pages): pages.load("pointerActionsPage.html") pointer_input = PointerInput(interaction.POINTER_PEN, "pen") # Make sure the pointer starts in a known location reset_actions = ActionBuilder(driver, mouse=pointer_input) reset_actions.pointer_action.move_to_location(x=0, y=0) reset_actions.perform() # Clear the events state driver.execute_script("allEvents.events = [];") pointerArea = driver.find_element(By.CSS_SELECTOR, "#pointerArea") actions = ActionBuilder(driver, mouse=pointer_input) center = _get_inview_center(pointerArea.rect, _get_viewport_rect(driver)) actions.pointer_action.move_to(pointerArea).pointer_down(pressure=0.36, tilt_x=-72, tilt_y=9, twist=86).move_to( pointerArea, x=5, y=10 ).pointer_up().move_to(pointerArea, x=5, y=10) actions.perform() events = _get_events(driver) assert events[3]["type"] == "pointerdown" assert events[3]["pageX"] == pytest.approx(center["x"], abs=1.0) assert events[3]["pageY"] == pytest.approx(center["y"], abs=1.0) assert events[3]["target"] == "pointerArea" assert events[3]["pointerType"] == "pen" # The default value of width and height for mouse and pen inputs is 1 assert round(events[3]["width"], 2) == 1 assert round(events[3]["height"], 2) == 1 assert round(events[3]["pressure"], 2) == 0.36 assert events[3]["tiltX"] == -72 assert events[3]["tiltY"] == 9 assert events[3]["twist"] == 86 assert events[6]["type"] == "pointermove" assert events[6]["target"] == "pointerArea" assert events[6]["pointerType"] == "pen" assert round(events[6]["width"], 2) == 1 assert round(events[6]["height"], 2) == 1 # The default value of pressure for all inputs is 0.5, other properties are 0 assert round(events[6]["pressure"], 2) == 0.5 assert events[6]["tiltX"] == 0 assert events[6]["tiltY"] == 0 assert events[6]["twist"] == 0 @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_touch_pointer_properties(driver, pages): pages.load("pointerActionsPage.html") pointerArea = driver.find_element(By.CSS_SELECTOR, "#pointerArea") center = _get_inview_center(pointerArea.rect, _get_viewport_rect(driver)) touch_input = PointerInput(interaction.POINTER_TOUCH, "touch") touch_chain = ActionBuilder(driver, mouse=touch_input) touch_chain.pointer_action.move_to(pointerArea).pointer_down( width=23, height=31, pressure=0.78, tilt_x=21, tilt_y=-8, twist=355 ).move_to( pointerArea, x=10, y=10, width=39, height=35, pressure=0.91, tilt_x=-19, tilt_y=62, twist=345 ).pointer_up().move_to( pointerArea, x=15, y=15 ) touch_chain.perform() events = _get_events(driver) assert len(events) == 7 event_types = [e["type"] for e in events] assert [ "pointerover", "pointerenter", "pointerdown", "pointermove", "pointerup", "pointerout", "pointerleave", ] == event_types assert events[2]["type"] == "pointerdown" assert events[2]["pageX"] == pytest.approx(center["x"], abs=1.0) assert events[2]["pageY"] == pytest.approx(center["y"], abs=1.0) assert events[2]["target"] == "pointerArea" assert events[2]["pointerType"] == "touch" assert round(events[2]["width"], 2) == 23 assert round(events[2]["height"], 2) == 31 assert round(events[2]["pressure"], 2) == 0.78 assert events[2]["tiltX"] == 21 assert events[2]["tiltY"] == -8 assert events[2]["twist"] == 355 assert events[3]["type"] == "pointermove" assert events[3]["pageX"] == pytest.approx(center["x"] + 10, abs=1.0) assert events[3]["pageY"] == pytest.approx(center["y"] + 10, abs=1.0) assert events[3]["target"] == "pointerArea" assert events[3]["pointerType"] == "touch" assert round(events[3]["width"], 2) == 39 assert round(events[3]["height"], 2) == 35 assert round(events[3]["pressure"], 2) == 0.91 assert events[3]["tiltX"] == -19 assert events[3]["tiltY"] == 62 assert events[3]["twist"] == 345 @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_scroll_mouse_wheel(driver, pages): pages.load("scrollingPage.html") driver.execute_script("document.scrollingElement.scrollTop = 0") scrollable = driver.find_element(By.CSS_SELECTOR, "#scrollable") wheel_input = WheelInput("wheel") actions = ActionBuilder(driver, wheel=wheel_input) actions.wheel_action.scroll(0, 0, 5, 10, 0, scrollable) actions.perform() events = _get_events(driver) assert len(events) == 1 assert events[0]["type"] == "wheel" assert events[0]["deltaX"] >= 5 assert events[0]["deltaY"] >= 10 assert events[0]["deltaZ"] == 0 assert events[0]["target"] == "scrollContent" def _perform_drag_and_drop_with_mouse(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" pages.load("draggableLists.html") dragReporter = driver.find_element(By.ID, "dragging_reports") toDrag = driver.find_element(By.ID, "rightitem-3") dragInto = driver.find_element(By.ID, "sortable1") actions = ActionBuilder(driver) pointer = actions.pointer_action pointer.click_and_hold(toDrag).move_to(driver.find_element(By.ID, "leftitem-4")).move_to(dragInto).release() assert "Nothing happened." == dragReporter.text actions.perform() assert "Nothing happened. DragOut" in dragReporter.text def _is_element_available(driver, id): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" try: driver.find_element(By.ID, id) return True except Exception: return False def _get_events(driver): """Return list of key events recorded in the test_keys_page fixture.""" events = driver.execute_script("return allEvents.events;") or [] # `key` values in `allEvents` may be escaped (see `escapeSurrogateHalf` in # test_keys_wdspec.html), so this converts them back into unicode literals. for e in events: # example: turn "U+d83d" (6 chars) into u"\ud83d" (1 char) if "key" in e and e["key"].startswith("U+"): key = e["key"] hex_suffix = key[key.index("+") + 1 :] e["key"] = chr(int(hex_suffix, 16)) # WebKit sets code as 'Unidentified' for unidentified key codes, but # tests expect ''. if "code" in e and e["code"] == "Unidentified": e["code"] = "" return events def _get_inview_center(elem_rect, viewport_rect): x = { "left": max(0, min(elem_rect["x"], elem_rect["x"] + elem_rect["width"])), "right": min(viewport_rect["width"], max(elem_rect["x"], elem_rect["x"] + elem_rect["width"])), } y = { "top": max(0, min(elem_rect["y"], elem_rect["y"] + elem_rect["height"])), "bottom": min(viewport_rect["height"], max(elem_rect["y"], elem_rect["y"] + elem_rect["height"])), } return { "x": (x["left"] + x["right"]) / 2, "y": (y["top"] + y["bottom"]) / 2, } def _get_viewport_rect(driver): return driver.execute_script( """ return { height: window.innerHeight || document.documentElement.clientHeight, width: window.innerWidth || document.documentElement.clientWidth, }; """ ) selenium-selenium-4.23.0/test/selenium/webdriver/common/api_example_tests.py0000664000175000017500000002256614646203155027304 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait def test_get_title(driver, pages): pages.load("simpleTest.html") title = driver.title assert "Hello WebDriver" == title def test_get_current_url(driver, pages, webserver): pages.load("simpleTest.html") url = driver.current_url assert webserver.where_is("simpleTest.html") == url def test_find_element_by_xpath(driver, pages): pages.load("simpleTest.html") elem = driver.find_element(By.XPATH, "//h1") assert "Heading" == elem.text def test_find_element_by_xpath_throw_no_such_element_exception(driver, pages): pages.load("simpleTest.html") with pytest.raises(NoSuchElementException): driver.find_element(By.XPATH, "//h4") def test_find_elements_by_xpath(driver, pages): pages.load("nestedElements.html") elems = driver.find_elements(By.XPATH, "//option") assert 48 == len(elems) assert "One" == elems[0].get_attribute("value") def test_find_elements_by_name(driver, pages): pages.load("xhtmlTest.html") elem = driver.find_element(By.NAME, "windowOne") assert "Open new window" == elem.text def test_find_elements_by_name_in_element_context(driver, pages): pages.load("nestedElements.html") elem = driver.find_element(By.NAME, "form2") sub_elem = elem.find_element(By.NAME, "selectomatic") assert "2" == sub_elem.get_attribute("id") def test_find_elements_by_link_text_in_element_context(driver, pages): pages.load("nestedElements.html") elem = driver.find_element(By.NAME, "div1") sub_elem = elem.find_element(By.LINK_TEXT, "hello world") assert "link1" == sub_elem.get_attribute("name") def test_find_element_by_id_in_element_context(driver, pages): pages.load("nestedElements.html") elem = driver.find_element(By.NAME, "form2") sub_elem = elem.find_element(By.ID, "2") assert "selectomatic" == sub_elem.get_attribute("name") def test_find_element_by_xpath_in_element_context(driver, pages): pages.load("nestedElements.html") elem = driver.find_element(By.NAME, "form2") sub_elem = elem.find_element(By.XPATH, "select") assert "2" == sub_elem.get_attribute("id") def test_find_element_by_xpath_in_element_context_not_found(driver, pages): pages.load("nestedElements.html") elem = driver.find_element(By.NAME, "form2") with pytest.raises(NoSuchElementException): elem.find_element(By.XPATH, "div") def test_should_be_able_to_enter_data_into_form_fields(driver, pages): pages.load("xhtmlTest.html") elem = driver.find_element(By.XPATH, "//form[@name='someForm']/input[@id='username']") elem.clear() elem.send_keys("some text") elem = driver.find_element(By.XPATH, "//form[@name='someForm']/input[@id='username']") assert "some text" == elem.get_attribute("value") def test_find_element_by_tag_name(driver, pages): pages.load("simpleTest.html") elems = driver.find_elements(By.TAG_NAME, "div") num_by_xpath = len(driver.find_elements(By.XPATH, "//div")) assert num_by_xpath == len(elems) elems = driver.find_elements(By.TAG_NAME, "iframe") assert 0 == len(elems) def test_find_element_by_tag_name_within_element(driver, pages): pages.load("simpleTest.html") div = driver.find_element(By.ID, "multiline") elems = div.find_elements(By.TAG_NAME, "p") assert len(elems) == 1 def test_switch_frame_by_name(driver, pages): pages.load("frameset.html") driver.switch_to.frame(driver.find_element(By.NAME, "third")) checkbox = driver.find_element(By.ID, "checky") checkbox.click() checkbox.submit() def test_is_enabled(driver, pages): pages.load("formPage.html") elem = driver.find_element(By.XPATH, "//input[@id='working']") assert elem.is_enabled() elem = driver.find_element(By.XPATH, "//input[@id='notWorking']") assert not elem.is_enabled() def test_is_selected_and_toggle(driver, pages): pages.load("formPage.html") elem = driver.find_element(By.ID, "multi") option_elems = elem.find_elements(By.XPATH, "option") assert option_elems[0].is_selected() option_elems[0].click() assert not option_elems[0].is_selected() option_elems[0].click() assert option_elems[0].is_selected() assert option_elems[2].is_selected() def test_navigate(driver, pages): pages.load("formPage.html") driver.find_element(By.ID, "imageButton").submit() WebDriverWait(driver, 3).until(EC.title_is("We Arrive Here")) driver.back() assert "We Leave From Here" == driver.title driver.forward() assert "We Arrive Here" == driver.title def test_get_attribute(driver, pages): url = pages.url("xhtmlTest.html") driver.get(url) elem = driver.find_element(By.ID, "id1") attr = elem.get_attribute("href") assert f"{url}#" == attr def test_get_implicit_attribute(driver, pages): pages.load("nestedElements.html") elems = driver.find_elements(By.XPATH, "//option") assert len(elems) >= 3 for i, elem in enumerate(elems[:3]): assert i == int(elem.get_attribute("index")) def test_get_dom_attribute(driver, pages): url = pages.url("formPage.html") driver.get(url) elem = driver.find_element(By.ID, "vsearchGadget") attr = elem.get_dom_attribute("accesskey") assert "4" == attr def test_get_property(driver, pages): url = pages.url("formPage.html") driver.get(url) elem = driver.find_element(By.ID, "withText") prop = elem.get_property("value") assert "Example text" == prop def test_execute_simple_script(driver, pages): pages.load("xhtmlTest.html") title = driver.execute_script("return document.title;") assert "XHTML Test Page" == title def test_execute_script_and_return_element(driver, pages): pages.load("xhtmlTest.html") elem = driver.execute_script("return document.getElementById('id1');") assert "WebElement" in str(type(elem)) def test_execute_script_with_args(driver, pages): pages.load("xhtmlTest.html") result = driver.execute_script("return arguments[0] == 'fish' ? 'fish' : 'not fish';", "fish") assert "fish" == result def test_execute_script_with_multiple_args(driver, pages): pages.load("xhtmlTest.html") result = driver.execute_script("return arguments[0] + arguments[1]", 1, 2) assert 3 == result def test_execute_script_with_element_args(driver, pages): pages.load("javascriptPage.html") button = driver.find_element(By.ID, "plainButton") result = driver.execute_script( "arguments[0]['flibble'] = arguments[0].getAttribute('id'); return arguments[0]['flibble'];", button ) assert "plainButton" == result def test_find_elements_by_partial_link_text(driver, pages): pages.load("xhtmlTest.html") elem = driver.find_element(By.PARTIAL_LINK_TEXT, "new window") elem.click() def test_is_element_displayed(driver, pages): pages.load("javascriptPage.html") visible = driver.find_element(By.ID, "displayed").is_displayed() not_visible = driver.find_element(By.ID, "hidden").is_displayed() assert visible assert not not_visible @pytest.mark.xfail_chrome def test_move_window_position(driver, pages): pages.load("blank.html") loc = driver.get_window_position() # note can't test 0,0 since some OS's dont allow that location # because of system toolbars new_x = 50 new_y = 50 if loc["x"] == new_x: new_x += 10 if loc["y"] == new_y: new_y += 10 driver.set_window_position(new_x, new_y) loc = driver.get_window_position() assert loc["x"] == new_x assert loc["y"] == new_y def test_change_window_size(driver, pages): pages.load("blank.html") size = driver.get_window_size() newSize = [600, 600] if size["width"] == 600: newSize[0] = 500 if size["height"] == 600: newSize[1] = 500 driver.set_window_size(newSize[0], newSize[1]) size = driver.get_window_size() assert size["width"] == newSize[0] assert size["height"] == newSize[1] @pytest.mark.xfail_firefox(raises=WebDriverException) @pytest.mark.xfail_remote @pytest.mark.xfail_safari def test_get_log_types(driver, pages): pages.load("blank.html") assert isinstance(driver.log_types, list) @pytest.mark.xfail_firefox(raises=WebDriverException) @pytest.mark.xfail_remote @pytest.mark.xfail_safari def test_get_log(driver, pages): pages.load("blank.html") for log_type in driver.log_types: log = driver.get_log(log_type) assert isinstance(log, list) selenium-selenium-4.23.0/test/selenium/webdriver/common/alerts_tests.py0000664000175000017500000002346614646203155026312 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import sys import pytest from selenium.common.exceptions import InvalidElementStateException from selenium.common.exceptions import NoAlertPresentException from selenium.common.exceptions import UnexpectedAlertPresentException from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait @pytest.fixture(autouse=True) def close_alert(driver): yield try: driver.switch_to.alert.dismiss() except Exception: pass def test_should_be_able_to_override_the_window_alert_method(driver, pages): pages.load("alerts.html") driver.execute_script("window.alert = function(msg) { document.getElementById('text').innerHTML = msg; }") driver.find_element(by=By.ID, value="alert").click() try: assert driver.find_element(By.ID, "text").text == "cheese" except Exception as e: # if we're here, likely the alert is displayed # not dismissing it will affect other tests try: _wait_for_alert(driver).dismiss() except Exception: pass raise e def test_should_allow_users_to_accept_an_alert_manually(driver, pages): pages.load("alerts.html") driver.find_element(by=By.ID, value="alert").click() alert = _wait_for_alert(driver) alert.accept() # If we can perform any action, we're good to go assert "Testing Alerts" == driver.title def test_should_allow_users_to_accept_an_alert_with_no_text_manually(driver, pages): pages.load("alerts.html") driver.find_element(By.ID, "empty-alert").click() alert = _wait_for_alert(driver) alert.accept() # If we can perform any action, we're good to go assert "Testing Alerts" == driver.title def test_should_get_text_of_alert_opened_in_set_timeout(driver, pages): pages.load("alerts.html") driver.find_element(By.ID, "slow-alert").click() # DO NOT WAIT OR SLEEP HERE # This is a regression test for a bug where only the first switchTo call would throw, # and only if it happens before the alert actually loads. alert = _wait_for_alert(driver) try: assert "Slow" == alert.text finally: alert.accept() def test_should_allow_users_to_dismiss_an_alert_manually(driver, pages): pages.load("alerts.html") driver.find_element(by=By.ID, value="alert").click() alert = _wait_for_alert(driver) alert.dismiss() # If we can perform any action, we're good to go assert "Testing Alerts" == driver.title def test_should_allow_auser_to_accept_aprompt(driver, pages): pages.load("alerts.html") driver.find_element(by=By.ID, value="prompt").click() alert = _wait_for_alert(driver) alert.accept() # If we can perform any action, we're good to go assert "Testing Alerts" == driver.title def test_should_allow_auser_to_dismiss_aprompt(driver, pages): pages.load("alerts.html") driver.find_element(by=By.ID, value="prompt").click() alert = _wait_for_alert(driver) alert.dismiss() # If we can perform any action, we're good to go assert "Testing Alerts" == driver.title def test_should_allow_auser_to_set_the_value_of_aprompt(driver, pages): pages.load("alerts.html") driver.find_element(by=By.ID, value="prompt").click() alert = _wait_for_alert(driver) alert.send_keys("cheese") alert.accept() result = driver.find_element(by=By.ID, value="text").text assert "cheese" == result @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_setting_the_value_of_an_alert_throws(driver, pages): pages.load("alerts.html") driver.find_element(By.ID, "alert").click() alert = _wait_for_alert(driver) with pytest.raises(InvalidElementStateException): alert.send_keys("cheese") alert.accept() @pytest.mark.xfail_chrome( condition=sys.platform == "darwin", reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=26", run=False ) @pytest.mark.xfail_edge( condition=sys.platform == "darwin", reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=26", run=False ) def test_alert_should_not_allow_additional_commands_if_dimissed(driver, pages): pages.load("alerts.html") driver.find_element(By.ID, "alert").click() alert = _wait_for_alert(driver) alert.dismiss() with pytest.raises(NoAlertPresentException): alert.text @pytest.mark.xfail_firefox(reason="Fails on travis") @pytest.mark.xfail_remote(reason="Fails on travis") @pytest.mark.xfail_safari def test_should_allow_users_to_accept_an_alert_in_aframe(driver, pages): pages.load("alerts.html") driver.switch_to.frame(driver.find_element(By.NAME, "iframeWithAlert")) driver.find_element(By.ID, "alertInFrame").click() alert = _wait_for_alert(driver) alert.accept() assert "Testing Alerts" == driver.title @pytest.mark.xfail_firefox(reason="Fails on travis") @pytest.mark.xfail_remote(reason="Fails on travis") @pytest.mark.xfail_safari def test_should_allow_users_to_accept_an_alert_in_anested_frame(driver, pages): pages.load("alerts.html") driver.switch_to.frame(driver.find_element(By.NAME, "iframeWithIframe")) driver.switch_to.frame(driver.find_element(By.NAME, "iframeWithAlert")) driver.find_element(By.ID, "alertInFrame").click() alert = _wait_for_alert(driver) alert.accept() assert "Testing Alerts" == driver.title def test_should_throw_an_exception_if_an_alert_has_not_been_dealt_with_and_dismiss_the_alert(): pass # //TODO(David) Complete this test def test_prompt_should_use_default_value_if_no_keys_sent(driver, pages): pages.load("alerts.html") driver.find_element(By.ID, "prompt-with-default").click() alert = _wait_for_alert(driver) alert.accept() txt = driver.find_element(By.ID, "text").text assert "This is a default value" == txt def test_prompt_should_have_null_value_if_dismissed(driver, pages): pages.load("alerts.html") driver.find_element(By.ID, "prompt-with-default").click() alert = _wait_for_alert(driver) alert.dismiss() assert "null" == driver.find_element(By.ID, "text").text def test_handles_two_alerts_from_one_interaction(driver, pages): pages.load("alerts.html") driver.find_element(By.ID, "double-prompt").click() alert1 = _wait_for_alert(driver) alert1.send_keys("brie") alert1.accept() alert2 = _wait_for_alert(driver) alert2.send_keys("cheddar") alert2.accept() assert driver.find_element(By.ID, "text1").text == "brie" assert driver.find_element(By.ID, "text2").text == "cheddar" @pytest.mark.xfail_safari def test_should_handle_alert_on_page_load(driver, pages): pages.load("alerts.html") driver.find_element(By.ID, "open-page-with-onload-alert").click() alert = _wait_for_alert(driver) value = alert.text alert.accept() assert "onload" == value def test_should_handle_alert_on_page_load_using_get(driver, pages): pages.load("pageWithOnLoad.html") alert = _wait_for_alert(driver) value = alert.text alert.accept() assert "onload" == value WebDriverWait(driver, 3).until( EC.text_to_be_present_in_element((By.TAG_NAME, "p"), "Page with onload event handler") ) @pytest.mark.xfail_chrome(reason="Non W3C conformant") @pytest.mark.xfail_edge(reason="Non W3C conformant") def test_should_handle_alert_on_page_before_unload(driver, pages): pages.load("pageWithOnBeforeUnloadMessage.html") element = driver.find_element(By.ID, "navigate") element.click() WebDriverWait(driver, 3).until(EC.title_is("Testing Alerts")) def test_should_allow_the_user_to_get_the_text_of_an_alert(driver, pages): pages.load("alerts.html") driver.find_element(by=By.ID, value="alert").click() alert = _wait_for_alert(driver) value = alert.text alert.accept() assert "cheese" == value def test_should_allow_the_user_to_get_the_text_of_aprompt(driver, pages): pages.load("alerts.html") driver.find_element(By.ID, "prompt").click() alert = _wait_for_alert(driver) value = alert.text alert.accept() assert "Enter something" == value def test_alert_should_not_allow_additional_commands_if_dismissed(driver, pages): pages.load("alerts.html") driver.find_element(By.ID, "alert").click() alert = _wait_for_alert(driver) alert.accept() with pytest.raises(NoAlertPresentException): alert.text @pytest.mark.xfail_firefox(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1279211") @pytest.mark.xfail_remote(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1279211") @pytest.mark.xfail_chrome @pytest.mark.xfail_edge def test_unexpected_alert_present_exception_contains_alert_text(driver, pages): pages.load("alerts.html") driver.find_element(by=By.ID, value="alert").click() alert = _wait_for_alert(driver) value = alert.text with pytest.raises(UnexpectedAlertPresentException) as e: pages.load("simpleTest.html") assert value == e.value.alert_text assert f"Alert Text: {value}" in str(e) def _wait_for_alert(driver): return WebDriverWait(driver, 3).until(EC.alert_is_present()) selenium-selenium-4.23.0/test/selenium/webdriver/common/click_tests.py0000664000175000017500000000264114646203155026075 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait @pytest.fixture(autouse=True) def loadPage(pages): pages.load("clicks.html") def test_can_click_on_alink_that_overflows_and_follow_it(driver): driver.find_element(By.ID, "overflowLink").click() WebDriverWait(driver, 3).until(EC.title_is("XHTML Test Page")) def test_clicking_alink_made_up_of_numbers_is_handled_correctly(driver): driver.find_element(By.LINK_TEXT, "333333").click() WebDriverWait(driver, 3).until(EC.title_is("XHTML Test Page")) selenium-selenium-4.23.0/test/selenium/webdriver/common/proxy_tests.py0000664000175000017500000001112414646203155026165 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.options import ArgOptions from selenium.webdriver.common.proxy import Proxy from selenium.webdriver.common.proxy import ProxyType MANUAL_PROXY = { "httpProxy": "some.url:1234", "ftpProxy": "ftp.proxy", "noProxy": "localhost, foo.localhost", "sslProxy": "ssl.proxy:1234", "socksProxy": "socks.proxy:65555", "socksUsername": "test", "socksPassword": "test", "socksVersion": 5, } PAC_PROXY = { "proxyAutoconfigUrl": "http://pac.url:1234", } AUTODETECT_PROXY = { "autodetect": True, } def test_can_add_manual_proxy_to_options(): proxy = Proxy() proxy.http_proxy = MANUAL_PROXY["httpProxy"] proxy.ftp_proxy = MANUAL_PROXY["ftpProxy"] proxy.no_proxy = MANUAL_PROXY["noProxy"] proxy.sslProxy = MANUAL_PROXY["sslProxy"] proxy.socksProxy = MANUAL_PROXY["socksProxy"] proxy.socksUsername = MANUAL_PROXY["socksUsername"] proxy.socksPassword = MANUAL_PROXY["socksPassword"] proxy.socksVersion = MANUAL_PROXY["socksVersion"] options = ArgOptions() options.proxy = proxy proxy_capabilities = MANUAL_PROXY.copy() proxy_capabilities["proxyType"] = "manual" assert proxy_capabilities == options.to_capabilities().get("proxy") def test_can_add_autodetect_proxy_to_options(): proxy = Proxy() proxy.auto_detect = AUTODETECT_PROXY["autodetect"] options = ArgOptions() options.proxy = proxy proxy_capabilities = AUTODETECT_PROXY.copy() proxy_capabilities["proxyType"] = "autodetect" assert proxy_capabilities == options.to_capabilities().get("proxy") def test_can_add_pacproxy_to_options(): proxy = Proxy() proxy.proxy_autoconfig_url = PAC_PROXY["proxyAutoconfigUrl"] options = ArgOptions() options.proxy = proxy proxy_capabilities = PAC_PROXY.copy() proxy_capabilities["proxyType"] = "pac" assert proxy_capabilities == options.to_capabilities().get("proxy") def test_can_not_change_initialized_proxy_type(): proxy = Proxy(raw={"proxyType": "direct"}) with pytest.raises(Exception): proxy.proxy_type = ProxyType.SYSTEM proxy = Proxy(raw={"proxyType": ProxyType.DIRECT}) with pytest.raises(Exception): proxy.proxy_type = ProxyType.SYSTEM def test_can_init_manual_proxy(): proxy = Proxy(raw=MANUAL_PROXY) assert ProxyType.MANUAL == proxy.proxy_type assert MANUAL_PROXY["httpProxy"] == proxy.http_proxy assert MANUAL_PROXY["ftpProxy"] == proxy.ftp_proxy assert MANUAL_PROXY["noProxy"] == proxy.no_proxy assert MANUAL_PROXY["sslProxy"] == proxy.sslProxy assert MANUAL_PROXY["socksProxy"] == proxy.socksProxy assert MANUAL_PROXY["socksUsername"] == proxy.socksUsername assert MANUAL_PROXY["socksPassword"] == proxy.socksPassword assert MANUAL_PROXY["socksVersion"] == proxy.socksVersion def test_can_init_autodetect_proxy(): proxy = Proxy(raw=AUTODETECT_PROXY) assert ProxyType.AUTODETECT == proxy.proxy_type assert AUTODETECT_PROXY["autodetect"] == proxy.auto_detect def test_can_init_pacproxy(): proxy = Proxy(raw=PAC_PROXY) assert ProxyType.PAC == proxy.proxy_type assert PAC_PROXY["proxyAutoconfigUrl"] == proxy.proxy_autoconfig_url def test_can_init_empty_proxy(): proxy = Proxy() assert ProxyType.UNSPECIFIED == proxy.proxy_type assert "" == proxy.http_proxy assert "" == proxy.ftp_proxy assert "" == proxy.no_proxy assert "" == proxy.sslProxy assert "" == proxy.socksProxy assert "" == proxy.socksUsername assert "" == proxy.socksPassword assert proxy.auto_detect is False assert "" == proxy.proxy_autoconfig_url assert proxy.socks_version is None options = ArgOptions() options.proxy = proxy proxy_capabilities = {} proxy_capabilities["proxyType"] = "unspecified" assert proxy_capabilities == options.to_capabilities().get("proxy") selenium-selenium-4.23.0/test/selenium/webdriver/common/bidi_tests.py0000664000175000017500000000666714646203155025733 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.by import By from selenium.webdriver.common.log import Log from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait @pytest.mark.xfail_firefox(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1819965") @pytest.mark.xfail_remote(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1819965") @pytest.mark.xfail_safari async def test_check_console_messages(driver, pages): async with driver.bidi_connection() as session: log = Log(driver, session) pages.load("javascriptPage.html") from selenium.webdriver.common.bidi.console import Console async with log.add_listener(Console.LOG) as messages: driver.execute_script("console.log('I love cheese')") assert messages["message"] == "I love cheese" @pytest.mark.xfail_firefox(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1819965") @pytest.mark.xfail_remote(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1819965") @pytest.mark.xfail_safari async def test_check_error_console_messages(driver, pages): async with driver.bidi_connection() as session: log = Log(driver, session) pages.load("javascriptPage.html") from selenium.webdriver.common.bidi.console import Console async with log.add_listener(Console.ERROR) as messages: driver.execute_script('console.error("I don\'t cheese")') driver.execute_script("console.log('I love cheese')") assert messages["message"] == "I don't cheese" @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote async def test_collect_js_exceptions(driver, pages): async with driver.bidi_connection() as session: log = Log(driver, session) pages.load("javascriptPage.html") async with log.add_js_error_listener() as exceptions: driver.find_element(By.ID, "throwing-mouseover").click() assert exceptions is not None assert exceptions.exception_details.stack_trace.call_frames[0].function_name == "onmouseover" @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote async def test_collect_log_mutations(driver, pages): async with driver.bidi_connection() as session: log = Log(driver, session) async with log.mutation_events() as event: pages.load("dynamic.html") driver.find_element(By.ID, "reveal").click() WebDriverWait(driver, 5).until(EC.visibility_of(driver.find_element(By.ID, "revealed"))) assert event["attribute_name"] == "style" assert event["current_value"] == "" assert event["old_value"] == "display:none;" selenium-selenium-4.23.0/test/selenium/webdriver/common/frame_switching_tests.py0000664000175000017500000004424414646203155030166 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import NoSuchFrameException from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait # ---------------------------------------------------------------------------------------------- # # Tests that WebDriver doesn't do anything fishy when it navigates to a page with frames. # # ---------------------------------------------------------------------------------------------- @pytest.fixture(autouse=True) def restore_default_context(driver): yield driver.switch_to.default_content() def test_should_always_focus_on_the_top_most_frame_after_anavigation_event(driver, pages): pages.load("frameset.html") driver.find_element(By.TAG_NAME, "frameset") # Test passes if this does not throw. def test_should_not_automatically_switch_focus_to_an_iframe_when_apage_containing_them_is_loaded(driver, pages): pages.load("iframes.html") driver.find_element(By.ID, "iframe_page_heading") def test_should_open_page_with_broken_frameset(driver, pages): pages.load("framesetPage3.html") frame1 = driver.find_element(By.ID, "first") driver.switch_to.frame(frame1) driver.switch_to.default_content() frame2 = driver.find_element(By.ID, "second") driver.switch_to.frame(frame2) # IE9 can not switch to this broken frame - it has no window. # ---------------------------------------------------------------------------------------------- # # Tests that WebDriver can switch to frames as expected. # # ---------------------------------------------------------------------------------------------- def test_should_be_able_to_switch_to_aframe_by_its_index(driver, pages): pages.load("frameset.html") driver.switch_to.frame(1) assert driver.find_element(By.ID, "pageNumber").text == "2" def test_should_be_able_to_switch_to_an_iframe_by_its_index(driver, pages): pages.load("iframes.html") driver.switch_to.frame(0) assert driver.find_element(By.NAME, "id-name1").get_attribute("value") == "name" def test_should_be_able_to_switch_to_aframe_by_its_name(driver, pages): pages.load("frameset.html") driver.switch_to.frame("fourth") assert driver.find_element(By.TAG_NAME, "frame").get_attribute("name") == "child1" def test_should_be_able_to_switch_to_an_iframe_by_its_name(driver, pages): pages.load("iframes.html") driver.switch_to.frame("iframe1-name") assert driver.find_element(By.NAME, "id-name1").get_attribute("value") == "name" def test_should_be_able_to_switch_to_aframe_by_its_id(driver, pages): pages.load("frameset.html") driver.switch_to.frame("fifth") assert driver.find_element(By.NAME, "windowOne").text == "Open new window" def test_should_be_able_to_switch_to_an_iframe_by_its_id(driver, pages): pages.load("iframes.html") driver.switch_to.frame("iframe1") assert driver.find_element(By.NAME, "id-name1").get_attribute("value") == "name" def test_should_be_able_to_switch_to_frame_with_name_containing_dot(driver, pages): pages.load("frameset.html") driver.switch_to.frame("sixth.iframe1") assert "Page number 3" in driver.find_element(By.TAG_NAME, "body").text def test_should_be_able_to_switch_to_aframe_using_apreviously_located_web_element(driver, pages): pages.load("frameset.html") frame = driver.find_element(By.TAG_NAME, "frame") driver.switch_to.frame(frame) assert driver.find_element(By.ID, "pageNumber").text == "1" def test_should_be_able_to_switch_to_an_iframe_using_apreviously_located_web_element(driver, pages): pages.load("iframes.html") frame = driver.find_element(By.TAG_NAME, "iframe") driver.switch_to.frame(frame) element = driver.find_element(By.NAME, "id-name1") assert element.get_attribute("value") == "name" def test_should_ensure_element_is_aframe_before_switching(driver, pages): pages.load("frameset.html") frame = driver.find_element(By.TAG_NAME, "frameset") with pytest.raises(NoSuchFrameException): driver.switch_to.frame(frame) def test_frame_searches_should_be_relative_to_the_currently_selected_frame(driver, pages): pages.load("frameset.html") driver.switch_to.frame("second") assert driver.find_element(By.ID, "pageNumber").text == "2" with pytest.raises(NoSuchElementException): driver.switch_to.frame(driver.find_element(By.NAME, "third")) driver.switch_to.default_content() driver.switch_to.frame(driver.find_element(By.NAME, "third")) with pytest.raises(NoSuchFrameException): driver.switch_to.frame("second") driver.switch_to.default_content() driver.switch_to.frame(driver.find_element(By.NAME, "second")) assert driver.find_element(By.ID, "pageNumber").text == "2" def test_should_select_child_frames_by_chained_calls(driver, pages): pages.load("frameset.html") driver.switch_to.frame(driver.find_element(By.NAME, "fourth")) driver.switch_to.frame(driver.find_element(By.NAME, "child2")) assert driver.find_element(By.ID, "pageNumber").text == "11" def test_should_throw_frame_not_found_exception_looking_up_sub_frames_with_super_frame_names(driver, pages): pages.load("frameset.html") driver.switch_to.frame(driver.find_element(By.NAME, "fourth")) with pytest.raises(NoSuchElementException): driver.switch_to.frame(driver.find_element(By.NAME, "second")) def test_should_throw_an_exception_when_aframe_cannot_be_found(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(NoSuchElementException): driver.switch_to.frame(driver.find_element(By.NAME, "Nothing here")) def test_should_throw_an_exception_when_aframe_cannot_be_found_by_index(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(NoSuchFrameException): driver.switch_to.frame(27) def test_should_be_able_to_switch_to_parent_frame(driver, pages): pages.load("frameset.html") driver.switch_to.frame(driver.find_element(By.NAME, "fourth")) driver.switch_to.parent_frame() driver.switch_to.frame(driver.find_element(By.NAME, "first")) assert driver.find_element(By.ID, "pageNumber").text == "1" @pytest.mark.xfail_safari def test_should_be_able_to_switch_to_parent_frame_from_asecond_level_frame(driver, pages): pages.load("frameset.html") driver.switch_to.frame(driver.find_element(By.NAME, "fourth")) driver.switch_to.frame(driver.find_element(By.NAME, "child1")) driver.switch_to.parent_frame() driver.switch_to.frame(driver.find_element(By.NAME, "child2")) assert driver.find_element(By.ID, "pageNumber").text == "11" def test_switching_to_parent_frame_from_default_context_is_no_op(driver, pages): pages.load("xhtmlTest.html") driver.switch_to.parent_frame() assert driver.title == "XHTML Test Page" def test_should_be_able_to_switch_to_parent_from_an_iframe(driver, pages): pages.load("iframes.html") driver.switch_to.frame(0) driver.switch_to.parent_frame() driver.find_element(By.ID, "iframe_page_heading") # ---------------------------------------------------------------------------------------------- # # General frame handling behavior tests # # ---------------------------------------------------------------------------------------------- def test_should_continue_to_refer_to_the_same_frame_once_it_has_been_selected(driver, pages): pages.load("frameset.html") driver.switch_to.frame(2) checkbox = driver.find_element(By.XPATH, "//input[@name='checky']") checkbox.click() checkbox.submit() # TODO(simon): this should not be needed, and is only here because IE's submit returns too # soon. WebDriverWait(driver, 3).until(EC.text_to_be_present_in_element((By.XPATH, "//p"), "Success!")) @pytest.mark.xfail_firefox(raises=WebDriverException, reason="https://github.com/mozilla/geckodriver/issues/610") @pytest.mark.xfail_remote(raises=WebDriverException, reason="https://github.com/mozilla/geckodriver/issues/610") @pytest.mark.xfail_safari @pytest.mark.xfail_chrome @pytest.mark.xfail_edge def test_should_focus_on_the_replacement_when_aframe_follows_alink_to_a_top_targeted_page(driver, pages): pages.load("frameset.html") driver.switch_to.frame(0) driver.find_element(By.LINK_TEXT, "top").click() expectedTitle = "XHTML Test Page" WebDriverWait(driver, 3).until(EC.title_is(expectedTitle)) WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.ID, "only-exists-on-xhtmltest"))) def test_should_allow_auser_to_switch_from_an_iframe_back_to_the_main_content_of_the_page(driver, pages): pages.load("iframes.html") driver.switch_to.frame(0) driver.switch_to.default_content() driver.find_element(By.ID, "iframe_page_heading") def test_should_allow_the_user_to_switch_to_an_iframe_and_remain_focused_on_it(driver, pages): pages.load("iframes.html") driver.switch_to.frame(0) driver.find_element(By.ID, "submitButton").click() assert get_text_of_greeting_element(driver) == "Success!" def get_text_of_greeting_element(driver): return WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.ID, "greeting"))).text def test_should_be_able_to_click_in_aframe(driver, pages): pages.load("frameset.html") driver.switch_to.frame("third") # This should replace frame "third" ... driver.find_element(By.ID, "submitButton").click() # driver should still be focused on frame "third" ... assert get_text_of_greeting_element(driver) == "Success!" # Make sure it was really frame "third" which was replaced ... driver.switch_to.default_content() driver.switch_to.frame("third") assert get_text_of_greeting_element(driver) == "Success!" def test_should_be_able_to_click_in_aframe_that_rewrites_top_window_location(driver, pages): pages.load("click_tests/issue5237.html") driver.switch_to.frame(driver.find_element(By.ID, "search")) driver.find_element(By.ID, "submit").click() driver.switch_to.default_content() WebDriverWait(driver, 3).until(EC.title_is("Target page for issue 5237")) def test_should_be_able_to_click_in_asub_frame(driver, pages): pages.load("frameset.html") driver.switch_to.frame(driver.find_element(By.ID, "sixth")) driver.switch_to.frame(driver.find_element(By.ID, "iframe1")) # This should replace frame "iframe1" inside frame "sixth" ... driver.find_element(By.ID, "submitButton").click() # driver should still be focused on frame "iframe1" inside frame "sixth" ... assert get_text_of_greeting_element(driver), "Success!" # Make sure it was really frame "iframe1" inside frame "sixth" which was replaced ... driver.switch_to.default_content() driver.switch_to.frame(driver.find_element(By.ID, "sixth")) driver.switch_to.frame(driver.find_element(By.ID, "iframe1")) assert driver.find_element(By.ID, "greeting").text == "Success!" def test_should_be_able_to_find_elements_in_iframes_by_xpath(driver, pages): pages.load("iframes.html") driver.switch_to.frame(driver.find_element(By.ID, "iframe1")) element = driver.find_element(By.XPATH, "//*[@id = 'changeme']") assert element is not None def test_get_current_url_returns_top_level_browsing_context_url(driver, pages): pages.load("frameset.html") assert "frameset.html" in driver.current_url driver.switch_to.frame(driver.find_element(By.NAME, "second")) assert "frameset.html" in driver.current_url def test_get_current_url_returns_top_level_browsing_context_url_for_iframes(driver, pages): pages.load("iframes.html") assert "iframes.html" in driver.current_url driver.switch_to.frame(driver.find_element(By.ID, "iframe1")) assert "iframes.html" in driver.current_url def test_should_be_able_to_switch_to_the_top_if_the_frame_is_deleted_from_under_us(driver, pages): pages.load("frame_switching_tests/deletingFrame.html") driver.switch_to.frame(driver.find_element(By.ID, "iframe1")) killIframe = driver.find_element(By.ID, "killIframe") killIframe.click() driver.switch_to.default_content() WebDriverWait(driver, 3).until_not(EC.presence_of_element_located((By.ID, "iframe1"))) addIFrame = driver.find_element(By.ID, "addBackFrame") addIFrame.click() WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.ID, "iframe1"))) driver.switch_to.frame(driver.find_element(By.ID, "iframe1")) WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.ID, "success"))) def test_should_be_able_to_switch_to_the_top_if_the_frame_is_deleted_from_under_us_with_frame_index(driver, pages): pages.load("frame_switching_tests/deletingFrame.html") iframe = 0 WebDriverWait(driver, 3).until(EC.frame_to_be_available_and_switch_to_it(iframe)) # we should be in the frame now killIframe = driver.find_element(By.ID, "killIframe") killIframe.click() driver.switch_to.default_content() addIFrame = driver.find_element(By.ID, "addBackFrame") addIFrame.click() WebDriverWait(driver, 3).until(EC.frame_to_be_available_and_switch_to_it(iframe)) WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.ID, "success"))) def test_frame_to_be_available_and_switch_to_it_using_string_inputs(driver, pages): # Similar to above test, but using `iframe = "iframe1"` instead of `iframe = 0` pages.load("frame_switching_tests/deletingFrame.html") iframe = "iframe1" WebDriverWait(driver, 3).until(EC.frame_to_be_available_and_switch_to_it(iframe)) # we should be in the frame now killIframe = driver.find_element(By.ID, "killIframe") killIframe.click() driver.switch_to.default_content() addIFrame = driver.find_element(By.ID, "addBackFrame") addIFrame.click() WebDriverWait(driver, 3).until(EC.frame_to_be_available_and_switch_to_it(iframe)) WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.ID, "success"))) def test_should_be_able_to_switch_to_the_top_if_the_frame_is_deleted_from_under_us_with_webelement(driver, pages): pages.load("frame_switching_tests/deletingFrame.html") iframe = driver.find_element(By.ID, "iframe1") WebDriverWait(driver, 3).until(EC.frame_to_be_available_and_switch_to_it(iframe)) # we should be in the frame now killIframe = driver.find_element(By.ID, "killIframe") killIframe.click() driver.switch_to.default_content() addIFrame = driver.find_element(By.ID, "addBackFrame") addIFrame.click() iframe = driver.find_element(By.ID, "iframe1") WebDriverWait(driver, 3).until(EC.frame_to_be_available_and_switch_to_it(iframe)) WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.ID, "success"))) # @pytest.mark.xfail_chrome(raises=NoSuchElementException) # @pytest.mark.xfail_edge(raises=NoSuchElementException) # @pytest.mark.xfail_firefox(raises=WebDriverException, # reason='https://github.com/mozilla/geckodriver/issues/614') # @pytest.mark.xfail_remote(raises=WebDriverException, # reason='https://github.com/mozilla/geckodriver/issues/614') # @pytest.mark.xfail_webkitgtk(raises=NoSuchElementException) # @pytest.mark.xfail_safari # def test_should_not_be_able_to_do_anything_the_frame_is_deleted_from_under_us(driver, pages): # pages.load("frame_switching_tests/deletingFrame.html") # driver.switch_to.frame(driver.find_element(By.ID, "iframe1")) # killIframe = driver.find_element(By.ID, "killIframe") # killIframe.click() # with pytest.raises(NoSuchFrameException): # driver.find_element(By.ID, "killIframe").click() def test_should_return_window_title_in_aframeset(driver, pages): pages.load("frameset.html") driver.switch_to.frame(driver.find_element(By.NAME, "third")) assert "Unique title" == driver.title def test_java_script_should_execute_in_the_context_of_the_current_frame(driver, pages): pages.load("frameset.html") assert driver.execute_script("return window == window.top") driver.switch_to.frame(driver.find_element(By.NAME, "third")) assert driver.execute_script("return window != window.top") @pytest.mark.xfail_chrome(reason="Fails on Travis") @pytest.mark.xfail_safari def test_should_not_switch_magically_to_the_top_window(driver, pages): pages.load("frame_switching_tests/bug4876.html") driver.switch_to.frame(0) WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.ID, "inputText"))) for i in range(20): try: input = WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.ID, "inputText"))) submit = WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.ID, "submitButton"))) input.clear() import random input.send_keys("rand%s" % int(random.random())) submit.click() finally: url = driver.execute_script("return window.location.href") # IE6 and Chrome add "?"-symbol to the end of the URL if url.endswith("?"): url = url[: len(url) - 1] assert pages.url("frame_switching_tests/bug4876_iframe.html") == url def test_get_should_switch_to_default_context(driver, pages): pages.load("iframes.html") driver.find_element(By.ID, "iframe1") driver.switch_to.frame(driver.find_element(By.ID, "iframe1")) driver.find_element(By.ID, "cheese") # Found on formPage.html but not on iframes.html. pages.load("iframes.html") # This must effectively switch_to.default_content(), too. driver.find_element(By.ID, "iframe1") selenium-selenium-4.23.0/test/selenium/webdriver/common/element_equality_tests.py0000664000175000017500000000307114646203155030354 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from selenium.webdriver.common.by import By def test_same_element_looked_up_different_ways_should_be_equal(driver, pages): pages.load("simpleTest.html") body = driver.find_element(By.TAG_NAME, "body") xbody = driver.find_elements(By.XPATH, "//body")[0] assert body == xbody def test_different_elements_are_not_equal(driver, pages): pages.load("simpleTest.html") body = driver.find_element(By.TAG_NAME, "body") div = driver.find_element(By.TAG_NAME, "div") assert body != div def test_same_elements_found_different_ways_should_not_be_duplicated_in_aset(driver, pages): pages.load("simpleTest.html") body = driver.find_element(By.TAG_NAME, "body") xbody = driver.find_elements(By.XPATH, "//body") s = set(xbody) s.add(body) assert 1 == len(s) selenium-selenium-4.23.0/test/selenium/webdriver/common/typing_tests.py0000664000175000017500000003242714646203155026327 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys def test_should_fire_key_press_events(driver, pages): pages.load("javascriptPage.html") keyReporter = driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys("a") result = driver.find_element(by=By.ID, value="result") assert "press:" in result.text def test_should_fire_key_down_events(driver, pages): pages.load("javascriptPage.html") keyReporter = driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys("I") result = driver.find_element(by=By.ID, value="result") assert "down" in result.text def test_should_fire_key_up_events(driver, pages): pages.load("javascriptPage.html") keyReporter = driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys("a") result = driver.find_element(by=By.ID, value="result") assert "up:" in result.text def test_should_type_lower_case_letters(driver, pages): pages.load("javascriptPage.html") keyReporter = driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys("abc def") assert keyReporter.get_attribute("value") == "abc def" def test_should_be_able_to_type_capital_letters(driver, pages): pages.load("javascriptPage.html") keyReporter = driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys("ABC DEF") assert keyReporter.get_attribute("value") == "ABC DEF" def test_should_be_able_to_type_quote_marks(driver, pages): pages.load("javascriptPage.html") keyReporter = driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys('"') assert keyReporter.get_attribute("value") == '"' def test_should_be_able_to_type_the_at_character(driver, pages): pages.load("javascriptPage.html") keyReporter = driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys("@") assert keyReporter.get_attribute("value") == "@" def test_should_be_able_to_mix_upper_and_lower_case_letters(driver, pages): pages.load("javascriptPage.html") keyReporter = driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys("me@eXample.com") assert keyReporter.get_attribute("value") == "me@eXample.com" def test_arrow_keys_should_not_be_printable(driver, pages): pages.load("javascriptPage.html") keyReporter = driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys(Keys.ARROW_LEFT) assert keyReporter.get_attribute("value") == "" def test_list_of_arrow_keys_should_not_be_printable(driver, pages): pages.load("javascriptPage.html") keyReporter = driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys([Keys.ARROW_LEFT]) assert keyReporter.get_attribute("value") == "" def test_should_be_able_to_use_arrow_keys(driver, pages): pages.load("javascriptPage.html") keyReporter = driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys("Tet", Keys.ARROW_LEFT, "s") assert keyReporter.get_attribute("value") == "Test" @pytest.mark.xfail_safari def test_will_simulate_akey_up_when_entering_text_into_input_elements(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyUp") element.send_keys("I like cheese") result = driver.find_element(by=By.ID, value="result") assert result.text == "I like cheese" @pytest.mark.xfail_safari def test_will_simulate_akey_down_when_entering_text_into_input_elements(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyDown") element.send_keys("I like cheese") result = driver.find_element(by=By.ID, value="result") # Because the key down gets the result before the input element is # filled, we're a letter short here assert result.text == "I like chees" @pytest.mark.xfail_safari def test_will_simulate_akey_press_when_entering_text_into_input_elements(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyPress") element.send_keys("I like cheese") result = driver.find_element(by=By.ID, value="result") # Because the key down gets the result before the input element is # filled, we're a letter short here assert result.text == "I like chees" @pytest.mark.xfail_safari def test_will_simulate_akey_up_when_entering_text_into_text_areas(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyUpArea") element.send_keys("I like cheese") result = driver.find_element(by=By.ID, value="result") assert result.text == "I like cheese" @pytest.mark.xfail_safari def test_will_simulate_akey_down_when_entering_text_into_text_areas(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyDownArea") element.send_keys("I like cheese") result = driver.find_element(by=By.ID, value="result") # Because the key down gets the result before the input element is # filled, we're a letter short here assert result.text == "I like chees" @pytest.mark.xfail_safari def test_will_simulate_akey_press_when_entering_text_into_text_areas(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyPressArea") element.send_keys("I like cheese") result = driver.find_element(by=By.ID, value="result") # Because the key down gets the result before the input element is # filled, we're a letter short here assert result.text == "I like chees" def test_should_report_key_code_of_arrow_keys_up_down_events(driver, pages): pages.load("javascriptPage.html") result = driver.find_element(by=By.ID, value="result") element = driver.find_element(by=By.ID, value="keyReporter") element.send_keys(Keys.ARROW_DOWN) assert "down: 40" in result.text.strip() assert "up: 40" in result.text.strip() element.send_keys(Keys.ARROW_UP) assert "down: 38" in result.text.strip() assert "up: 38" in result.text.strip() element.send_keys(Keys.ARROW_LEFT) assert "down: 37" in result.text.strip() assert "up: 37" in result.text.strip() element.send_keys(Keys.ARROW_RIGHT) assert "down: 39" in result.text.strip() assert "up: 39" in result.text.strip() # And leave no rubbish/printable keys in the "keyReporter" assert element.get_attribute("value") == "" def test_numeric_non_shift_keys(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyReporter") numericLineCharsNonShifted = "`1234567890-=[]\\,.'/42" element.send_keys(numericLineCharsNonShifted) assert element.get_attribute("value") == numericLineCharsNonShifted @pytest.mark.xfail_firefox(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1255258") @pytest.mark.xfail_remote(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1255258") def test_numeric_shift_keys(driver, pages): pages.load("javascriptPage.html") result = driver.find_element(by=By.ID, value="result") element = driver.find_element(by=By.ID, value="keyReporter") numericShiftsEtc = '~!@#$%^&*()_+{}:i"<>?|END~' element.send_keys(numericShiftsEtc) assert element.get_attribute("value") == numericShiftsEtc assert "up: 16" in result.text.strip() def test_lower_case_alpha_keys(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyReporter") lowerAlphas = "abcdefghijklmnopqrstuvwxyz" element.send_keys(lowerAlphas) assert element.get_attribute("value") == lowerAlphas @pytest.mark.xfail_firefox(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1255258") @pytest.mark.xfail_remote(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1255258") def test_uppercase_alpha_keys(driver, pages): pages.load("javascriptPage.html") result = driver.find_element(by=By.ID, value="result") element = driver.find_element(by=By.ID, value="keyReporter") upperAlphas = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" element.send_keys(upperAlphas) assert element.get_attribute("value") == upperAlphas assert "up: 16" in result.text.strip() @pytest.mark.xfail_firefox(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1255258") @pytest.mark.xfail_remote(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1255258") def test_all_printable_keys(driver, pages): pages.load("javascriptPage.html") result = driver.find_element(by=By.ID, value="result") element = driver.find_element(by=By.ID, value="keyReporter") allPrintable = "!\"#$%&'()*+,-./0123456789:<=>?@ ABCDEFGHIJKLMNOPQRSTUVWXYZ [\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" element.send_keys(allPrintable) assert element.get_attribute("value") == allPrintable assert "up: 16" in result.text.strip() def test_arrow_keys_and_page_up_and_down(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyReporter") element.send_keys(f"a{Keys.LEFT}b{Keys.RIGHT}{Keys.UP}{Keys.DOWN}{Keys.PAGE_UP}{Keys.PAGE_DOWN}1") assert element.get_attribute("value") == "ba1" # def test_home_and_end_and_page_up_and_page_down_keys(driver, pages): # // FIXME: macs don't have HOME keys, would PGUP work? # if (Platform.getCurrent().is(Platform.MAC)) { # return # } # pages.load("javascriptPage.html") # element = driver.find_element(by=By.ID, value="keyReporter") # element.send_keys("abc" + Keys.HOME + "0" + Keys.LEFT + Keys.RIGHT + # Keys.PAGE_UP + Keys.PAGE_DOWN + Keys.END + "1" + Keys.HOME + # "0" + Keys.PAGE_UP + Keys.END + "111" + Keys.HOME + "00") # assert element.get_attribute("value") == "0000abc1111" def test_delete_and_backspace_keys(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyReporter") element.send_keys("abcdefghi") assert element.get_attribute("value") == "abcdefghi" element.send_keys(Keys.LEFT, Keys.LEFT, Keys.DELETE) assert element.get_attribute("value") == "abcdefgi" element.send_keys(Keys.LEFT, Keys.LEFT, Keys.BACK_SPACE) assert element.get_attribute("value") == "abcdfgi" @pytest.mark.xfail_firefox(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1255258") @pytest.mark.xfail_remote(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1255258") def test_special_space_keys(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyReporter") element.send_keys("abcd" + Keys.SPACE + "fgh" + Keys.SPACE + "ij") assert element.get_attribute("value") == "abcd fgh ij" @pytest.mark.xfail_firefox(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1255258") @pytest.mark.xfail_remote(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1255258") @pytest.mark.xfail_safari def test_numberpad_and_function_keys(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyReporter") element.send_keys( "abcd{}{}{}{}{}{}{}{}{}{}{}{}abcd".format( Keys.MULTIPLY, Keys.SUBTRACT, Keys.ADD, Keys.DECIMAL, Keys.SEPARATOR, Keys.NUMPAD0, Keys.NUMPAD9, Keys.ADD, Keys.SEMICOLON, Keys.EQUALS, Keys.DIVIDE, Keys.NUMPAD3, ) ) assert element.get_attribute("value") == "abcd*-+.,09+;=/3abcd" element.clear() element.send_keys("FUNCTION" + Keys.F2 + "-KEYS" + Keys.F2) element.send_keys("" + Keys.F2 + "-TOO" + Keys.F2) assert element.get_attribute("value") == "FUNCTION-KEYS-TOO" @pytest.mark.xfail_safari def test_shift_selection_deletes(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyReporter") element.send_keys("abcd efgh") assert element.get_attribute("value") == "abcd efgh" element.send_keys(Keys.SHIFT, Keys.LEFT, Keys.LEFT, Keys.LEFT) element.send_keys(Keys.DELETE) assert element.get_attribute("value") == "abcd e" def test_should_type_into_input_elements_that_have_no_type_attribute(driver, pages): pages.load("formPage.html") element = driver.find_element(by=By.ID, value="no-type") element.send_keys("Should Say Cheese") assert element.get_attribute("value") == "Should Say Cheese" def test_should_type_an_integer(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyReporter") element.send_keys(1234) assert element.get_attribute("value") == "1234" selenium-selenium-4.23.0/test/selenium/webdriver/common/upload_tests.py0000664000175000017500000000553514646203155026301 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import os import pytest from selenium.webdriver.common.by import By from selenium.webdriver.remote.webelement import WebElement @pytest.fixture def get_local_path(): current_dir = os.path.dirname(os.path.realpath(__file__)) def wrapped(filename): return os.path.join(current_dir, filename) return wrapped def test_can_upload_file(driver, pages, get_local_path): pages.load("upload.html") driver.find_element(By.ID, "upload").send_keys(get_local_path("test_file.txt")) driver.find_element(By.ID, "go").click() driver.switch_to.frame(driver.find_element(By.ID, "upload_target")) body = driver.find_element(By.CSS_SELECTOR, "body").text assert "test_file.txt" in body def test_can_upload_two_files(driver, pages, get_local_path): pages.load("upload.html") two_file_paths = get_local_path("test_file.txt") + "\n" + get_local_path("test_file2.txt") driver.find_element(By.ID, "upload").send_keys(two_file_paths) driver.find_element(By.ID, "go").click() driver.switch_to.frame(driver.find_element(By.ID, "upload_target")) body = driver.find_element(By.CSS_SELECTOR, "body").text assert "test_file.txt" in body assert "test_file2.txt" in body @pytest.mark.xfail_firefox @pytest.mark.xfail_chrome @pytest.mark.xfail_edge @pytest.mark.xfail_safari def test_file_is_uploaded_to_remote_machine_on_select(driver, pages, get_local_path): uploaded_files = [] original_upload_func = WebElement._upload def mocked_upload_func(self, filename): uploaded_files.append(filename) return original_upload_func(self, filename) WebElement._upload = mocked_upload_func try: pages.load("upload.html") two_file_paths = get_local_path("test_file.txt") + "\n" + get_local_path("test_file2.txt") driver.find_element(By.ID, "upload").send_keys(two_file_paths) assert len(uploaded_files) == 2 assert uploaded_files[0] == get_local_path("test_file.txt") assert uploaded_files[1] == get_local_path("test_file2.txt") finally: WebElement._upload = original_upload_func selenium-selenium-4.23.0/test/selenium/webdriver/common/select_class_tests.py0000664000175000017500000003144514646203155027460 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import UnexpectedTagNameException from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import Select disabledSelect = {"name": "no-select", "values": ["Foo"]} disabledSingleSelect = {"name": "single_disabled", "values": ["Enabled", "Disabled"]} disabledMultiSelect = {"name": "multi_disabled", "values": ["Enabled", "Disabled"]} singleSelectValues1 = { "name": "selectomatic", "values": ["One", "Two", "Four", "Still learning how to count, apparently"], } singleSelectValues2 = {"name": "redirect", "values": ["One", "Two"]} singleSelectValuesWithSpaces = { "name": "select_with_spaces", "values": ["One", "Two", "Four", "Still learning how to count, apparently"], } multiSelectValues1 = {"name": "multi", "values": ["Eggs", "Ham", "Sausages", "Onion gravy"]} multiSelectValues2 = {"name": "select_empty_multiple", "values": ["select_1", "select_2", "select_3", "select_4"]} def test_select_by_index_single(driver, pages): pages.load("formPage.html") for select in [singleSelectValues1]: sel = Select(driver.find_element(By.NAME, select["name"])) for x in range(len(select["values"])): sel.select_by_index(x) assert sel.first_selected_option.text == select["values"][x] @pytest.mark.xfail_safari(reason="options incorrectly reported as enabled") def test_raises_exception_select_by_index_single_disabled(driver, pages): pages.load("formPage.html") sel = Select(driver.find_element(By.NAME, disabledSingleSelect["name"])) with pytest.raises(NotImplementedError): sel.select_by_index(1) def test_select_by_value_single(driver, pages): pages.load("formPage.html") for select in [singleSelectValues1]: sel = Select(driver.find_element(By.NAME, select["name"])) for x in range(len(select["values"])): sel.select_by_value(select["values"][x].lower()) assert sel.first_selected_option.text == select["values"][x] @pytest.mark.xfail_safari(reason="options incorrectly reported as enabled") def test_raises_exception_select_by_value_single_disabled(driver, pages): pages.load("formPage.html") sel = Select(driver.find_element(By.NAME, disabledSingleSelect["name"])) with pytest.raises(NotImplementedError): sel.select_by_value(disabledSingleSelect["values"][1].lower()) def test_select_by_visible_text_single(driver, pages): pages.load("formPage.html") for select in [singleSelectValues1]: sel = Select(driver.find_element(By.NAME, select["name"])) for x in range(len(select["values"])): print(select["values"][x]) sel.select_by_visible_text(select["values"][x]) assert sel.first_selected_option.text == select["values"][x] @pytest.mark.xfail_safari(reason="options incorrectly reported as enabled") def test_raises_exception_select_by_text_single_disabled(driver, pages): pages.load("formPage.html") sel = Select(driver.find_element(By.NAME, disabledSingleSelect["name"])) with pytest.raises(NotImplementedError): sel.select_by_visible_text(disabledSingleSelect["values"][1]) def test_select_by_index_multiple(driver, pages): pages.load("formPage.html") for select in [multiSelectValues1, multiSelectValues2]: sel = Select(driver.find_element(By.NAME, select["name"])) sel.deselect_all() for x in range(len(select["values"])): sel.select_by_index(x) selected = sel.all_selected_options assert len(selected) == x + 1 for j in range(len(selected)): assert selected[j].text == select["values"][j] @pytest.mark.xfail_safari(reason="options incorrectly reported as enabled") def test_raises_exception_select_by_index_multiple_disabled(driver, pages): pages.load("formPage.html") sel = Select(driver.find_element(By.NAME, disabledMultiSelect["name"])) with pytest.raises(NotImplementedError): sel.select_by_index(1) def test_select_by_value_multiple(driver, pages): pages.load("formPage.html") for select in [multiSelectValues1, multiSelectValues2]: sel = Select(driver.find_element(By.NAME, select["name"])) sel.deselect_all() for x in range(len(select["values"])): sel.select_by_value(select["values"][x].lower()) selected = sel.all_selected_options assert len(selected) == x + 1 for j in range(len(selected)): assert selected[j].text == select["values"][j] @pytest.mark.xfail_safari(reason="options incorrectly reported as enabled") def test_raises_exception_select_by_value_multiple_disabled(driver, pages): pages.load("formPage.html") sel = Select(driver.find_element(By.NAME, disabledMultiSelect["name"])) with pytest.raises(NotImplementedError): sel.select_by_value(disabledMultiSelect["values"][1].lower()) def test_select_by_visible_text_multiple(driver, pages): pages.load("formPage.html") for select in [multiSelectValues1, multiSelectValues2]: sel = Select(driver.find_element(By.NAME, select["name"])) sel.deselect_all() for x in range(len(select["values"])): sel.select_by_visible_text(select["values"][x]) selected = sel.all_selected_options assert len(selected) == x + 1 for j in range(len(selected)): assert selected[j].text == select["values"][j] @pytest.mark.xfail_safari(reason="options incorrectly reported as enabled") def test_raises_exception_select_by_text_multiple_disabled(driver, pages): pages.load("formPage.html") sel = Select(driver.find_element(By.NAME, disabledMultiSelect["name"])) with pytest.raises(NotImplementedError): sel.select_by_visible_text(disabledMultiSelect["values"][1]) def test_deselect_all_single(driver, pages): pages.load("formPage.html") for select in [singleSelectValues1, singleSelectValues2]: with pytest.raises(NotImplementedError): Select(driver.find_element(By.NAME, select["name"])).deselect_all() def test_deselect_all_multiple(driver, pages): pages.load("formPage.html") for select in [multiSelectValues1, multiSelectValues2]: sel = Select(driver.find_element(By.NAME, select["name"])) sel.deselect_all() assert len(sel.all_selected_options) == 0 def test_deselect_by_index_single(driver, pages): pages.load("formPage.html") for select in [singleSelectValues1, singleSelectValues2]: with pytest.raises(NotImplementedError): Select(driver.find_element(By.NAME, select["name"])).deselect_by_index(0) def test_deselect_by_value_single(driver, pages): pages.load("formPage.html") for select in [singleSelectValues1, singleSelectValues2]: with pytest.raises(NotImplementedError): Select(driver.find_element(By.NAME, select["name"])).deselect_by_value(select["values"][0].lower()) def test_deselect_by_visible_text_single(driver, pages): pages.load("formPage.html") for select in [singleSelectValues1, singleSelectValues2]: with pytest.raises(NotImplementedError): Select(driver.find_element(By.NAME, select["name"])).deselect_by_visible_text(select["values"][0]) def test_deselect_by_index_multiple(driver, pages): pages.load("formPage.html") for select in [multiSelectValues1, multiSelectValues2]: sel = Select(driver.find_element(By.NAME, select["name"])) sel.deselect_all() sel.select_by_index(0) sel.select_by_index(1) sel.select_by_index(2) sel.select_by_index(3) sel.deselect_by_index(1) sel.deselect_by_index(3) selected = sel.all_selected_options assert len(selected) == 2 assert selected[0].text == select["values"][0] assert selected[1].text == select["values"][2] def test_deselect_by_value_multiple(driver, pages): pages.load("formPage.html") for select in [multiSelectValues1, multiSelectValues2]: sel = Select(driver.find_element(By.NAME, select["name"])) sel.deselect_all() sel.select_by_index(0) sel.select_by_index(1) sel.select_by_index(2) sel.select_by_index(3) sel.deselect_by_value(select["values"][1].lower()) sel.deselect_by_value(select["values"][3].lower()) selected = sel.all_selected_options assert len(selected) == 2 assert selected[0].text == select["values"][0] assert selected[1].text == select["values"][2] def test_deselect_by_visible_text_multiple(driver, pages): pages.load("formPage.html") for select in [multiSelectValues1, multiSelectValues2]: sel = Select(driver.find_element(By.NAME, select["name"])) sel.deselect_all() sel.select_by_index(0) sel.select_by_index(1) sel.select_by_index(2) sel.select_by_index(3) sel.deselect_by_visible_text(select["values"][1]) sel.deselect_by_visible_text(select["values"][3]) selected = sel.all_selected_options assert len(selected) == 2 assert selected[0].text == select["values"][0] assert selected[1].text == select["values"][2] def test_get_options(driver, pages): pages.load("formPage.html") for select in [singleSelectValues1, singleSelectValues2, multiSelectValues1, multiSelectValues2]: opts = Select(driver.find_element(By.NAME, select["name"])).options assert len(opts) == len(select["values"]) for i in range(len(opts)): assert opts[i].text == select["values"][i] def test_get_all_selected_options_single(driver, pages): pages.load("formPage.html") for select in [singleSelectValues1, singleSelectValues2, disabledSelect]: opts = Select(driver.find_element(By.NAME, select["name"])).all_selected_options assert len(opts) == 1 assert opts[0].text == select["values"][0] def test_get_all_selected_options_multiple(driver, pages): pages.load("formPage.html") opts = Select(driver.find_element(By.NAME, multiSelectValues1["name"])).all_selected_options assert len(opts) == 2 assert opts[0].text, multiSelectValues1["values"][0] assert opts[1].text, multiSelectValues1["values"][2] opts = Select(driver.find_element(By.NAME, multiSelectValues2["name"])).all_selected_options assert len(opts) == 0 def test_get_first_selected_option_single(driver, pages): pages.load("formPage.html") for select in [singleSelectValues1, singleSelectValues2]: opt = Select(driver.find_element(By.NAME, select["name"])).first_selected_option assert opt.text == select["values"][0] def test_get_first_selected_option_multiple(driver, pages): pages.load("formPage.html") opt = Select(driver.find_element(By.NAME, multiSelectValues1["name"])).first_selected_option assert opt.text == multiSelectValues1["values"][0] opt = Select(driver.find_element(By.NAME, multiSelectValues2["name"])).all_selected_options assert len(opt) == 0 def test_raises_exception_for_invalid_tag_name(driver, pages): pages.load("formPage.html") with pytest.raises(UnexpectedTagNameException): Select(driver.find_element(By.TAG_NAME, "div")) def test_deselect_by_index_non_existent(driver, pages): pages.load("formPage.html") for select in [multiSelectValues1, multiSelectValues2]: with pytest.raises(NoSuchElementException): Select(driver.find_element(By.NAME, select["name"])).deselect_by_index(10) def test_deselect_by_value_non_existent(driver, pages): pages.load("formPage.html") for select in [multiSelectValues1, multiSelectValues2]: with pytest.raises(NoSuchElementException): Select(driver.find_element(By.NAME, select["name"])).deselect_by_value("not there") def test_deselect_by_text_non_existent(driver, pages): pages.load("formPage.html") for select in [multiSelectValues1, multiSelectValues2]: with pytest.raises(NoSuchElementException): Select(driver.find_element(By.NAME, select["name"])).deselect_by_visible_text("not there") selenium-selenium-4.23.0/test/selenium/webdriver/common/clear_tests.py0000664000175000017500000000565014646203155026101 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import InvalidElementStateException from selenium.webdriver.common.by import By def test_writable_text_input_should_clear(driver, pages): pages.load("readOnlyPage.html") element = driver.find_element(By.ID, "writableTextInput") element.clear() assert "" == element.get_attribute("value") @pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") @pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") def test_text_input_should_not_clear_when_disabled(driver, pages): pages.load("readOnlyPage.html") element = driver.find_element(By.ID, "textInputNotEnabled") assert not element.is_enabled() with pytest.raises(InvalidElementStateException): element.clear() def test_text_input_should_not_clear_when_read_only(driver, pages): pages.load("readOnlyPage.html") element = driver.find_element(By.ID, "readOnlyTextInput") with pytest.raises(InvalidElementStateException): element.clear() def test_writable_text_area_should_clear(driver, pages): pages.load("readOnlyPage.html") element = driver.find_element(By.ID, "writableTextArea") element.clear() assert "" == element.get_attribute("value") @pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") @pytest.mark.xfail_edge(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4743") def test_text_area_should_not_clear_when_disabled(driver, pages): pages.load("readOnlyPage.html") element = driver.find_element(By.ID, "textAreaNotEnabled") with pytest.raises(InvalidElementStateException): element.clear() def test_text_area_should_not_clear_when_read_only(driver, pages): pages.load("readOnlyPage.html") element = driver.find_element(By.ID, "textAreaReadOnly") with pytest.raises(InvalidElementStateException): element.clear() def test_content_editable_area_should_clear(driver, pages): pages.load("readOnlyPage.html") element = driver.find_element(By.ID, "content-editable") element.clear() assert "" == element.text selenium-selenium-4.23.0/test/selenium/webdriver/common/bidi_script_tests.py0000664000175000017500000000636014646203155027305 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait @pytest.mark.xfail_safari def test_logs_console_messages(driver, pages): pages.load("bidi/logEntryAdded.html") log_entries = [] driver.script.add_console_message_handler(log_entries.append) driver.find_element(By.ID, "jsException").click() driver.find_element(By.ID, "consoleLog").click() WebDriverWait(driver, 5).until(lambda _: log_entries) log_entry = log_entries[0] assert log_entry.level == "info" assert log_entry.method == "log" assert log_entry.text == "Hello, world!" assert log_entry.type_ == "console" @pytest.mark.xfail_safari def test_logs_console_errors(driver, pages): pages.load("bidi/logEntryAdded.html") log_entries = [] def log_error(entry): if entry.level == "error": log_entries.append(entry) driver.script.add_console_message_handler(log_error) driver.find_element(By.ID, "consoleLog").click() driver.find_element(By.ID, "consoleError").click() WebDriverWait(driver, 5).until(lambda _: log_entries) assert len(log_entries) == 1 log_entry = log_entries[0] assert log_entry.level == "error" assert log_entry.method == "error" assert log_entry.text == "I am console error" assert log_entry.type_ == "console" @pytest.mark.xfail_safari def test_logs_multiple_console_messages(driver, pages): pages.load("bidi/logEntryAdded.html") log_entries = [] driver.script.add_console_message_handler(log_entries.append) driver.script.add_console_message_handler(log_entries.append) driver.find_element(By.ID, "jsException").click() driver.find_element(By.ID, "consoleLog").click() WebDriverWait(driver, 5).until(lambda _: len(log_entries) > 1) assert len(log_entries) == 2 @pytest.mark.xfail_safari def test_removes_console_message_handler(driver, pages): pages.load("bidi/logEntryAdded.html") log_entries1 = [] log_entries2 = [] id = driver.script.add_console_message_handler(log_entries1.append) driver.script.add_console_message_handler(log_entries2.append) driver.find_element(By.ID, "consoleLog").click() WebDriverWait(driver, 5).until(lambda _: len(log_entries1) and len(log_entries2)) driver.script.remove_console_message_handler(id) driver.find_element(By.ID, "consoleLog").click() WebDriverWait(driver, 5).until(lambda _: len(log_entries2) == 2) assert len(log_entries1) == 1 selenium-selenium-4.23.0/test/selenium/webdriver/common/page_loading_tests.py0000664000175000017500000001156714646203155027430 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import pytest # # from selenium.common.exceptions import WebDriverException # from selenium.webdriver.common.by import By # from selenium.webdriver.support.wait import WebDriverWait # from selenium.webdriver.support import expected_conditions as EC def test_should_wait_for_document_to_be_loaded(driver, pages): pages.load("simpleTest.html") assert driver.title == "Hello WebDriver" # Disabled till Java WebServer is used # def test_should_follow_redirects_sent_in_the_http_response_headers(driver, pages): # pages.load("redirect.html") # assert driver.title == "We Arrive Here" # Disabled till the Java WebServer is used # def test_should_follow_meta_redirects(driver, pages): # pages.load("metaRedirect.html") # assert driver.title == "We Arrive Here" # def test_should_be_able_to_get_afragment_on_the_current_page(driver, pages): # pages.load("xhtmlTest.html") # location = driver.current_url # driver.get(location + "#text") # driver.find_element(by=By.ID, value="id1") # @pytest.mark.xfail_firefox(raises=WebDriverException) # @pytest.mark.xfail_remote(raises=WebDriverException) # def test_should_return_when_getting_aurl_that_does_not_resolve(driver): # # Of course, we're up the creek if this ever does get registered # driver.get("http://www.thisurldoesnotexist.comx/") # @pytest.mark.xfail_firefox(raises=WebDriverException) # @pytest.mark.xfail_remote(raises=WebDriverException) # def test_should_return_when_getting_aurl_that_does_not_connect(driver): # # Here's hoping that there's nothing here. There shouldn't be # driver.get("http://localhost:3001") # def test_should_be_able_to_load_apage_with_framesets_and_wait_until_all_frames_are_loaded() { # driver.get(pages.framesetPage) # # driver.switchTo().frame(0) # WebElement pageNumber = driver.findElement(By.xpath("#span[@id='pageNumber']")) # self.assertEqual((pageNumber.getText().trim(), equalTo("1")) # # driver.switchTo().defaultContent().switchTo().frame(1) # pageNumber = driver.findElement(By.xpath("#span[@id='pageNumber']")) # self.assertEqual((pageNumber.getText().trim(), equalTo("2")) # Need to implement this decorator # @NeedsFreshDriver # def test_sould_do_nothing_if_there_is_nothing_to_go_back_to() { # originalTitle = driver.getTitle(); # driver.get(pages.formPage); # driver.back(); # # We may have returned to the browser's home page # self.assertEqual(driver.title, anyOf(equalTo(originalTitle), equalTo("We Leave From Here"))); # @pytest.mark.xfail_safari # def test_should_be_able_to_navigate_back_in_the_browser_history(driver, pages): # pages.load("formPage.html") # driver.find_element(by=By.ID, value="imageButton").submit() # WebDriverWait(driver, 3).until(EC.title_is("We Arrive Here")) # driver.back() # assert driver.title == "We Leave From Here" # @pytest.mark.xfail_safari # def test_should_be_able_to_navigate_back_in_the_browser_history_in_presence_of_iframes(driver, pages): # pages.load("xhtmlTest.html") # driver.find_element(by=By.NAME, value="sameWindow").click() # assert driver.title == "This page has iframes" # driver.back() # assert driver.title == "XHTML Test Page" # def test_should_be_able_to_navigate_forwards_in_the_browser_history(driver, pages): # pages.load("formPage.html") # driver.find_element(by=By.ID, value="imageButton").submit() # WebDriverWait(driver, 3).until(EC.title_is("We Arrive Here")) # driver.back() # assert driver.title == "We Leave From Here" # driver.forward() # assert driver.title == "We Arrive Here" # @pytest.mark.xfail_ie # @pytest.mark.xfail_firefox(run=False) # @pytest.mark.xfail_remote(run=False) # @pytest.mark.xfail_chrome(run=False) # @pytest.mark.xfail_edge(run=False) # def test_should_not_hang_if_document_open_call_is_never_followed_by_document_close_call(driver, pages): # pages.load("document_write_in_onload.html") # driver.find_element(By.XPATH, "//body") # def test_should_be_able_to_refresh_apage(driver, pages): # pages.load("xhtmlTest.html") # driver.refresh() # assert driver.title == "XHTML Test Page" selenium-selenium-4.23.0/test/selenium/webdriver/marionette/0000775000175000017500000000000014646203155024070 5ustar carstencarstenselenium-selenium-4.23.0/test/selenium/webdriver/marionette/mn_set_context_tests.py0000664000175000017500000000166714646203155030727 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. def test_we_can_switch_context_to_chrome(driver): driver.set_context("chrome") assert 1 == driver.execute_script("var c = Components.classes; return 1;") selenium-selenium-4.23.0/test/selenium/webdriver/marionette/__init__.py0000664000175000017500000000142314646203155026201 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.23.0/test/selenium/webdriver/marionette/conftest.py0000664000175000017500000000236614646203155026276 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver import Firefox from selenium.webdriver.firefox.options import Options as FirefoxOptions @pytest.fixture def options(): options = FirefoxOptions() return options @pytest.fixture def driver_class(): return Firefox @pytest.fixture def driver_kwargs(options): return {"options": options} @pytest.fixture def driver(driver_class, driver_kwargs): driver = driver_class(**driver_kwargs) yield driver driver.quit() selenium-selenium-4.23.0/test/selenium/webdriver/marionette/mn_service_tests.py0000664000175000017500000000225114646203155030016 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from selenium.webdriver.firefox.service import Service def test_command_line_args(): service = Service(service_args=["--log", "trace"]) found = False args = service.command_line_args() for idx in range(len(args) - 1): if args[idx] == "--log" and args[idx + 1] == "trace": found = True break assert found, "Provided arguments do not exist in array" selenium-selenium-4.23.0/test/selenium/webdriver/marionette/mn_context_tests.py0000664000175000017500000000215614646203155030046 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. def test_context_sets_correct_context_and_returns(driver): def get_context(): return driver.execute("GET_CONTEXT").pop("value") assert get_context() == driver.CONTEXT_CONTENT with driver.context(driver.CONTEXT_CHROME): assert get_context() == driver.CONTEXT_CHROME assert get_context() == driver.CONTEXT_CONTENT selenium-selenium-4.23.0/test/selenium/webdriver/marionette/mn_options_tests.py0000664000175000017500000001132714646203155030055 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.by import By from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.common.options import PageLoadStrategy from selenium.webdriver.firefox.firefox_binary import FirefoxBinary from selenium.webdriver.firefox.firefox_profile import FirefoxProfile from selenium.webdriver.firefox.options import Log from selenium.webdriver.firefox.options import Options @pytest.fixture def driver_kwargs(driver_kwargs): driver_kwargs["options"] = Options() return driver_kwargs class TestIntegration: def test_we_can_pass_options(self, driver, pages): pages.load("formPage.html") driver.find_element(By.ID, "cheese") class TestUnit: def test_ctor(self): opts = Options() assert opts._binary is None assert not opts._preferences assert opts._profile is None assert not opts._arguments assert isinstance(opts.log, Log) def test_binary(self): opts = Options() assert opts.binary is None other_binary = FirefoxBinary() assert other_binary != opts.binary opts.binary = other_binary assert other_binary == opts.binary path = "/path/to/binary" opts.binary = path assert isinstance(opts.binary, FirefoxBinary) assert opts.binary._start_cmd == path def test_prefs(self): opts = Options() assert len(opts.preferences) == 0 assert isinstance(opts.preferences, dict) opts.set_preference("spam", "ham") assert len(opts.preferences) == 1 opts.set_preference("eggs", True) assert len(opts.preferences) == 2 opts.set_preference("spam", "spam") assert len(opts.preferences) == 2 assert opts.preferences == {"spam": "spam", "eggs": True} def test_profile(self, tmpdir_factory): opts = Options() assert opts.profile is None other_profile = FirefoxProfile() assert other_profile != opts.profile opts.profile = other_profile assert other_profile == opts.profile opts.profile = str(tmpdir_factory.mktemp("profile")) assert isinstance(opts.profile, FirefoxProfile) def test_arguments(self): opts = Options() assert len(opts.arguments) == 0 opts.add_argument("--foo") assert len(opts.arguments) == 1 opts.arguments.append("--bar") assert len(opts.arguments) == 2 assert opts.arguments == ["--foo", "--bar"] def test_to_capabilities(self): opts = Options() firefox_caps = DesiredCapabilities.FIREFOX.copy() firefox_caps.update({"pageLoadStrategy": PageLoadStrategy.normal}) assert opts.to_capabilities() == firefox_caps profile = FirefoxProfile() opts.profile = profile caps = opts.to_capabilities() assert "moz:firefoxOptions" in caps assert "profile" in caps["moz:firefoxOptions"] assert isinstance(caps["moz:firefoxOptions"]["profile"], str) assert caps["moz:firefoxOptions"]["profile"] == profile.encoded opts.add_argument("--foo") caps = opts.to_capabilities() assert "moz:firefoxOptions" in caps assert "args" in caps["moz:firefoxOptions"] assert caps["moz:firefoxOptions"]["args"] == ["--foo"] binary = FirefoxBinary() opts.binary = binary caps = opts.to_capabilities() assert "moz:firefoxOptions" in caps assert "binary" in caps["moz:firefoxOptions"] assert isinstance(caps["moz:firefoxOptions"]["binary"], str) assert caps["moz:firefoxOptions"]["binary"] == binary._start_cmd opts.set_preference("spam", "ham") caps = opts.to_capabilities() assert "moz:firefoxOptions" in caps assert "prefs" in caps["moz:firefoxOptions"] assert isinstance(caps["moz:firefoxOptions"]["prefs"], dict) assert caps["moz:firefoxOptions"]["prefs"]["spam"] == "ham" selenium-selenium-4.23.0/test/selenium/webdriver/support/0000775000175000017500000000000014646203155023435 5ustar carstencarstenselenium-selenium-4.23.0/test/selenium/webdriver/support/expected_conditions_tests.py0000664000175000017500000000657414646203155031277 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import TimeoutException from selenium.webdriver.common.by import By from selenium.webdriver.remote.webelement import WebElement from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait def test_any_of_true(driver, pages): pages.load("simpleTest.html") WebDriverWait(driver, 0.1).until(EC.any_of(EC.title_is("Nope"), EC.title_is("Hello WebDriver"))) def test_any_of_false(driver, pages): pages.load("simpleTest.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.1).until(EC.any_of(EC.title_is("Nope"), EC.title_is("Still Nope"))) def test_all_of_true(driver, pages): pages.load("simpleTest.html") results = WebDriverWait(driver, 0.1).until( EC.all_of(EC.title_is("Hello WebDriver"), EC.visibility_of_element_located((By.ID, "oneline"))) ) assert results[0] is True assert isinstance(results[1], WebElement) def test_all_of_false(driver, pages): pages.load("simpleTest.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.1).until(EC.all_of(EC.title_is("Nope"), EC.title_is("Still Nope"))) def test_none_of_true(driver, pages): pages.load("simpleTest.html") WebDriverWait(driver, 0.1).until(EC.none_of(EC.title_is("Nope"), EC.title_is("Still Nope"))) def test_none_of_false(driver, pages): pages.load("simpleTest.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.1).until(EC.none_of(EC.title_is("Nope"), EC.title_is("Hello WebDriver"))) def test_clickable_locator_true(driver, pages): pages.load("simpleTest.html") WebDriverWait(driver, 0.1).until(EC.element_to_be_clickable((By.ID, "multilinelink"))) def test_clickable_locator_false(driver, pages): pages.load("simpleTest.html") with pytest.raises(TimeoutException): # text element, should not be clickable WebDriverWait(driver, 0.1).until(EC.element_to_be_clickable((By.ID, "hiddenline"))) def test_clickable_element_true(driver, pages): pages.load("simpleTest.html") target = (By.ID, "multilinelink") element = driver.find_element(*target) # grab element at locator WebDriverWait(driver, 0.1).until(EC.element_to_be_clickable(element)) def test_clickable_element_false(driver, pages): pages.load("simpleTest.html") with pytest.raises(TimeoutException): target = (By.ID, "hiddenline") # text, should not be clickable element = driver.find_element(*target) # grab element at locator WebDriverWait(driver, 0.1).until(EC.element_to_be_clickable(element)) selenium-selenium-4.23.0/test/selenium/webdriver/support/__init__.py0000664000175000017500000000142314646203155025546 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.23.0/test/selenium/webdriver/support/relative_by_tests.py0000664000175000017500000001517114646203155027543 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.common.by import By from selenium.webdriver.support.relative_locator import locate_with from selenium.webdriver.support.relative_locator import with_tag_name def test_should_be_able_to_find_first_one(driver, pages): pages.load("relative_locators.html") lowest = driver.find_element(By.ID, "below") el = driver.find_element(with_tag_name("p").above(lowest)) assert el.get_attribute("id") == "mid" def test_should_be_able_to_find_first_one_by_locator(driver, pages): pages.load("relative_locators.html") el = driver.find_element(with_tag_name("p").above({By.ID: "below"})) assert el.get_attribute("id") == "mid" def test_should_be_able_to_find_elements_above_another(driver, pages): pages.load("relative_locators.html") lowest = driver.find_element(By.ID, "below") elements = driver.find_elements(with_tag_name("p").above(lowest)) ids = [el.get_attribute("id") for el in elements] assert "above" in ids assert "mid" in ids def test_should_be_able_to_find_elements_above_another_by_locator(driver, pages): pages.load("relative_locators.html") elements = driver.find_elements(with_tag_name("p").above({By.ID: "below"})) ids = [el.get_attribute("id") for el in elements] assert "above" in ids assert "mid" in ids def test_should_be_able_to_combine_filters(driver, pages): pages.load("relative_locators.html") elements = driver.find_elements( with_tag_name("td") .above(driver.find_element(By.ID, "center")) .to_right_of(driver.find_element(By.ID, "second")) ) ids = [el.get_attribute("id") for el in elements] assert "third" in ids def test_should_be_able_to_combine_filters_by_locator(driver, pages): pages.load("relative_locators.html") elements = driver.find_elements(with_tag_name("td").above({By.ID: "center"}).to_right_of({By.ID: "second"})) ids = [el.get_attribute("id") for el in elements] assert "third" in ids def test_should_be_able_to_use_css_selectors(driver, pages): pages.load("relative_locators.html") elements = driver.find_elements( locate_with(By.CSS_SELECTOR, "td") .above(driver.find_element(By.ID, "center")) .to_right_of(driver.find_element(By.ID, "second")) ) ids = [el.get_attribute("id") for el in elements] assert "third" in ids def test_should_be_able_to_use_css_selectors_by_locator(driver, pages): pages.load("relative_locators.html") elements = driver.find_elements( locate_with(By.CSS_SELECTOR, "td").above({By.ID: "center"}).to_right_of({By.ID: "second"}) ) ids = [el.get_attribute("id") for el in elements] assert "third" in ids def test_should_be_able_to_use_xpath(driver, pages): pages.load("relative_locators.html") elements = driver.find_elements( locate_with(By.XPATH, "//td[1]") .below(driver.find_element(By.ID, "second")) .above(driver.find_element(By.ID, "seventh")) ) ids = [el.get_attribute("id") for el in elements] assert "fourth" in ids def test_should_be_able_to_use_xpath_by_locator(driver, pages): pages.load("relative_locators.html") elements = driver.find_elements(locate_with(By.XPATH, "//td[1]").below({By.ID: "second"}).above({By.ID: "seventh"})) ids = [el.get_attribute("id") for el in elements] assert "fourth" in ids def test_no_such_element_is_raised_rather_than_index_error(driver, pages): pages.load("relative_locators.html") with pytest.raises(NoSuchElementException) as exc: anchor = driver.find_element(By.ID, "second") driver.find_element(locate_with(By.ID, "nonexistentid").above(anchor)) assert "Cannot locate relative element with: {'id': 'nonexistentid'}" in exc.value.msg def test_no_such_element_is_raised_rather_than_index_error_by_locator(driver, pages): pages.load("relative_locators.html") with pytest.raises(NoSuchElementException) as exc: driver.find_element(locate_with(By.ID, "nonexistentid").above({By.ID: "second"})) assert "Cannot locate relative element with: {'id': 'nonexistentid'}" in exc.value.msg def test_near_locator_should_find_near_elements(driver, pages): pages.load("relative_locators.html") rect1 = driver.find_element(By.ID, "rect1") el = driver.find_element(locate_with(By.ID, "rect2").near(rect1)) assert el.get_attribute("id") == "rect2" def test_near_locator_should_find_near_elements_by_locator(driver, pages): pages.load("relative_locators.html") el = driver.find_element(locate_with(By.ID, "rect2").near({By.ID: "rect1"})) assert el.get_attribute("id") == "rect2" def test_near_locator_should_not_find_far_elements(driver, pages): pages.load("relative_locators.html") rect3 = driver.find_element(By.ID, "rect3") with pytest.raises(NoSuchElementException) as exc: driver.find_element(locate_with(By.ID, "rect4").near(rect3)) assert "Cannot locate relative element with: {'id': 'rect4'}" in exc.value.msg def test_near_locator_should_not_find_far_elements_by_locator(driver, pages): pages.load("relative_locators.html") with pytest.raises(NoSuchElementException) as exc: driver.find_element(locate_with(By.ID, "rect4").near({By.ID: "rect3"})) assert "Cannot locate relative element with: {'id': 'rect4'}" in exc.value.msg def test_near_locator_should_find_far_elements(driver, pages): pages.load("relative_locators.html") rect3 = driver.find_element(By.ID, "rect3") el = driver.find_element(locate_with(By.ID, "rect4").near(rect3, 100)) assert el.get_attribute("id") == "rect4" def test_near_locator_should_find_far_elements_by_locator(driver, pages): pages.load("relative_locators.html") el = driver.find_element(locate_with(By.ID, "rect4").near({By.ID: "rect3"}, 100)) assert el.get_attribute("id") == "rect4" selenium-selenium-4.23.0/test/selenium/webdriver/support/event_firing_webdriver_tests.py0000664000175000017500000002117714646203155031771 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from io import BytesIO import pytest from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.common.actions.action_builder import ActionBuilder from selenium.webdriver.common.by import By from selenium.webdriver.support.events import AbstractEventListener from selenium.webdriver.support.events import EventFiringWebDriver from selenium.webdriver.support.ui import WebDriverWait @pytest.fixture def log(): log = BytesIO() yield log log.close() def test_should_fire_navigation_events(driver, log, pages): class EventListener(AbstractEventListener): def before_navigate_to(self, url, driver): log.write(("before_navigate_to %s" % url.split("/")[-1]).encode()) def after_navigate_to(self, url, driver): log.write(("after_navigate_to %s" % url.split("/")[-1]).encode()) def before_navigate_back(self, driver): log.write(b"before_navigate_back") def after_navigate_back(self, driver): log.write(b"after_navigate_back") def before_navigate_forward(self, driver): log.write(b"before_navigate_forward") def after_navigate_forward(self, driver): log.write(b"after_navigate_forward") ef_driver = EventFiringWebDriver(driver, EventListener()) ef_driver.get(pages.url("formPage.html")) ef_driver.find_element(by=By.ID, value="imageButton").submit() WebDriverWait(ef_driver, 5).until(lambda d: d.title == "We Arrive Here") assert ef_driver.title == "We Arrive Here" ef_driver.back() assert ef_driver.title == "We Leave From Here" ef_driver.forward() assert ef_driver.title == "We Arrive Here" assert ( b"before_navigate_to formPage.html" b"after_navigate_to formPage.html" b"before_navigate_back" b"after_navigate_back" b"before_navigate_forward" b"after_navigate_forward" ) == log.getvalue() @pytest.mark.xfail_safari def test_should_fire_click_event(driver, log, pages): class EventListener(AbstractEventListener): def before_click(self, element, driver): log.write(b"before_click") def after_click(self, element, driver): log.write(b"after_click") ef_driver = EventFiringWebDriver(driver, EventListener()) ef_driver.get(pages.url("clicks.html")) ef_driver.find_element(By.ID, "overflowLink").click() assert ef_driver.title == "XHTML Test Page" assert b"before_click" + b"after_click" == log.getvalue() def test_should_fire_change_value_event(driver, log, pages): class EventListener(AbstractEventListener): def before_change_value_of(self, element, driver): log.write(b"before_change_value_of") def after_change_value_of(self, element, driver): log.write(b"after_change_value_of") ef_driver = EventFiringWebDriver(driver, EventListener()) ef_driver.get(pages.url("readOnlyPage.html")) element = ef_driver.find_element(By.ID, "writableTextInput") element.clear() assert "" == element.get_attribute("value") ef_driver.get(pages.url("javascriptPage.html")) keyReporter = ef_driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys("abc def") assert keyReporter.get_attribute("value") == "abc def" assert ( b"before_change_value_of" b"after_change_value_of" b"before_change_value_of" b"after_change_value_of" ) == log.getvalue() def test_should_fire_find_event(driver, log, pages): class EventListener(AbstractEventListener): def before_find(self, by, value, driver): log.write((f"before_find by {by} {value}").encode()) def after_find(self, by, value, driver): log.write((f"after_find by {by} {value}").encode()) ef_driver = EventFiringWebDriver(driver, EventListener()) ef_driver.get(pages.url("simpleTest.html")) e = ef_driver.find_element(By.ID, "oneline") assert "A single line of text" == e.text e = ef_driver.find_element(By.XPATH, "/html/body/p[1]") assert "A single line of text" == e.text ef_driver.get(pages.url("frameset.html")) elements = ef_driver.find_elements(By.CSS_SELECTOR, "frame#sixth") assert 1 == len(elements) assert "frame" == elements[0].tag_name.lower() assert "sixth" == elements[0].get_attribute("id") assert ( b"before_find by id oneline" b"after_find by id oneline" b"before_find by xpath /html/body/p[1]" b"after_find by xpath /html/body/p[1]" b"before_find by css selector frame#sixth" b"after_find by css selector frame#sixth" ) == log.getvalue() def test_should_call_listener_when_an_exception_is_thrown(driver, log, pages): class EventListener(AbstractEventListener): def on_exception(self, exception, driver): if isinstance(exception, NoSuchElementException): log.write(b"NoSuchElementException is thrown") ef_driver = EventFiringWebDriver(driver, EventListener()) ef_driver.get(pages.url("simpleTest.html")) with pytest.raises(NoSuchElementException): ef_driver.find_element(By.ID, "foo") assert b"NoSuchElementException is thrown" == log.getvalue() def test_should_unwrap_element_args_when_calling_scripts(driver, log, pages): ef_driver = EventFiringWebDriver(driver, AbstractEventListener()) ef_driver.get(pages.url("javascriptPage.html")) button = ef_driver.find_element(By.ID, "plainButton") value = ef_driver.execute_script( "arguments[0]['flibble'] = arguments[0].getAttribute('id'); return arguments[0]['flibble']", button ) assert "plainButton" == value def test_should_unwrap_element_args_when_switching_frames(driver, log, pages): ef_driver = EventFiringWebDriver(driver, AbstractEventListener()) ef_driver.get(pages.url("iframes.html")) frame = ef_driver.find_element(By.ID, "iframe1") ef_driver.switch_to.frame(frame) assert "click me!" == ef_driver.find_element(By.ID, "imageButton").get_attribute("alt") def test_should_be_able_to_access_wrapped_instance_from_event_calls(driver): class EventListener(AbstractEventListener): def before_navigate_to(url, d): assert driver is d ef_driver = EventFiringWebDriver(driver, EventListener()) wrapped_driver = ef_driver.wrapped_driver assert driver is wrapped_driver def test_using_kwargs(driver, pages): ef_driver = EventFiringWebDriver(driver, AbstractEventListener()) ef_driver.get(pages.url("javascriptPage.html")) ef_driver.get_cookie(name="cookie_name") element = ef_driver.find_element(By.ID, "plainButton") element.get_attribute(name="id") def test_missing_attributes_raise_error(driver, pages): ef_driver = EventFiringWebDriver(driver, AbstractEventListener()) with pytest.raises(AttributeError): ef_driver.attribute_should_not_exist ef_driver.get(pages.url("readOnlyPage.html")) element = ef_driver.find_element(By.ID, "writableTextInput") with pytest.raises(AttributeError): element.attribute_should_not_exist def test_can_use_pointer_input_with_event_firing_webdriver(driver, pages): ef_driver = EventFiringWebDriver(driver, AbstractEventListener()) pages.load("javascriptPage.html") to_click = ef_driver.find_element(By.ID, "clickField") actions = ActionBuilder(ef_driver) pointer = actions.pointer_action pointer.move_to(to_click).click() actions.perform() assert to_click.get_attribute("value") == "Clicked" @pytest.mark.xfail_safari def test_can_use_key_input_with_event_firing_webdriver(driver, pages): ef_driver = EventFiringWebDriver(driver, AbstractEventListener()) pages.load("javascriptPage.html") ef_driver.find_element(By.ID, "keyUp").click() actions = ActionBuilder(ef_driver) key = actions.key_action key.send_keys("Success") actions.perform() result = ef_driver.find_element(By.ID, "result") assert result.text == "Success" selenium-selenium-4.23.0/test/selenium/webdriver/support/conftest.py0000664000175000017500000000173514646203155025642 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. def pytest_generate_tests(metafunc): if "driver" in metafunc.fixturenames and metafunc.config.option.drivers: metafunc.parametrize("driver", metafunc.config.option.drivers, indirect=True) selenium-selenium-4.23.0/test/unit/0000775000175000017500000000000014646203155017066 5ustar carstencarstenselenium-selenium-4.23.0/test/unit/__init__.py0000664000175000017500000000142314646203155021177 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.23.0/test/unit/selenium/0000775000175000017500000000000014646203155020707 5ustar carstencarstenselenium-selenium-4.23.0/test/unit/selenium/__init__.py0000664000175000017500000000142314646203155023020 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.23.0/test/unit/selenium/webdriver/0000775000175000017500000000000014646203155022700 5ustar carstencarstenselenium-selenium-4.23.0/test/unit/selenium/webdriver/firefox/0000775000175000017500000000000014646203155024342 5ustar carstencarstenselenium-selenium-4.23.0/test/unit/selenium/webdriver/firefox/firefox_options_tests.py0000664000175000017500000001302314646203155031352 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import InvalidArgumentException from selenium.webdriver.common.options import PageLoadStrategy from selenium.webdriver.common.proxy import Proxy from selenium.webdriver.common.proxy import ProxyType from selenium.webdriver.firefox.firefox_binary import FirefoxBinary from selenium.webdriver.firefox.firefox_profile import FirefoxProfile from selenium.webdriver.firefox.options import Options @pytest.fixture def options(): return Options() def test_set_binary_with_firefox_binary(options): binary = FirefoxBinary("foo") options.binary = binary assert options.binary_location == "foo" def test_set_binary_with_path(options): options.binary = "/foo" assert options.binary_location == "/foo" def test_get_binary(options): options.binary = "/foo" assert options.binary._start_cmd == "/foo" def test_set_binary_location(options): options.binary_location = "/foo" assert options.binary_location == "/foo" def test_get_binary_location(options): options._binary_location = "/foo" assert options.binary_location == "/foo" def test_set_preference(options): options.set_preference("foo", "bar") assert options._preferences["foo"] == "bar" def test_get_preferences(options): options._preferences = {"foo": "bar"} assert options.preferences["foo"] == "bar" def test_set_proxy(options): proxy = Proxy({"proxyType": ProxyType.MANUAL}) options.proxy = proxy assert options._proxy == proxy def test_set_proxy_isnt_in_moz_prefix(options): proxy = Proxy({"proxyType": ProxyType.MANUAL}) options.proxy = proxy caps = options.to_capabilities() assert caps["proxy"]["proxyType"] == "manual" assert caps.get("moz:firefoxOptions") == {"prefs": {"remote.active-protocols": 3}} def test_raises_exception_if_proxy_is_not_proxy_object(options): with pytest.raises(InvalidArgumentException): options.proxy = "foo" def test_get_proxy(options): options._proxy = "foo" assert options.proxy == "foo" def test_set_profile_with_firefox_profile(options): profile = FirefoxProfile() options.profile = profile assert options._profile == profile def test_set_profile_with_path(options): options.profile = None assert isinstance(options._profile, FirefoxProfile) def test_get_profile(options): options._profile = "foo" assert options.profile == "foo" def test_add_arguments(options): options.add_argument("foo") assert "foo" in options._arguments def test_get_arguments(options): options._arguments = ["foo"] assert "foo" in options.arguments def test_raises_exception_if_argument_is_falsy(options): with pytest.raises(ValueError): options.add_argument(None) def test_set_log_level(options): options.log.level = "debug" assert options.log.level == "debug" def test_creates_capabilities(options): profile = FirefoxProfile() options._arguments = ["foo"] options._binary_location = "/bar" options._preferences = {"foo": "bar"} options.proxy = Proxy({"proxyType": ProxyType.MANUAL}) options._profile = profile options.log.level = "debug" caps = options.to_capabilities() opts = caps.get(Options.KEY) assert opts assert "foo" in opts["args"] assert opts["binary"] == "/bar" assert opts["prefs"]["foo"] == "bar" assert isinstance(opts["profile"], str) and opts["profile"] assert caps["proxy"]["proxyType"] == "manual" assert opts["log"]["level"] == "debug" def test_starts_with_default_capabilities(options): from selenium.webdriver import DesiredCapabilities caps = DesiredCapabilities.FIREFOX.copy() caps.update({"pageLoadStrategy": PageLoadStrategy.normal}) assert options._caps == caps def test_is_a_baseoptions(options): from selenium.webdriver.common.options import BaseOptions assert isinstance(options, BaseOptions) def test_raises_exception_with_invalid_page_load_strategy(options): with pytest.raises(ValueError): options.page_load_strategy = "never" def test_set_page_load_strategy(options): options.page_load_strategy = PageLoadStrategy.normal assert options._caps["pageLoadStrategy"] == PageLoadStrategy.normal def test_get_page_load_strategy(options): options._page_load_strategy = PageLoadStrategy.normal assert options._caps["pageLoadStrategy"] == PageLoadStrategy.normal def test_creates_capabilities_with_page_load_strategy(options): options.page_load_strategy = PageLoadStrategy.eager caps = options.to_capabilities() assert caps["pageLoadStrategy"] == PageLoadStrategy.eager def test_enables_firefox_mobile(options): options.enable_mobile() result_caps = options.to_capabilities() assert result_caps["moz:firefoxOptions"]["androidPackage"] == "org.mozilla.firefox" selenium-selenium-4.23.0/test/unit/selenium/webdriver/remote/0000775000175000017500000000000014646203155024173 5ustar carstencarstenselenium-selenium-4.23.0/test/unit/selenium/webdriver/remote/error_handler_tests.py0000664000175000017500000002674414646203155030632 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common import exceptions from selenium.webdriver.remote.errorhandler import ErrorCode from selenium.webdriver.remote.errorhandler import ErrorHandler @pytest.fixture def handler(): yield ErrorHandler() def test_does_not_raise_exception_on_success(handler): assert handler.check_response({"status": ErrorCode.SUCCESS}) is None assert handler.check_response({}) is None @pytest.mark.parametrize("code", ErrorCode.NO_SUCH_ELEMENT) def test_raises_exception_for_no_such_element(handler, code): with pytest.raises(exceptions.NoSuchElementException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.NO_SUCH_FRAME) def test_raises_exception_for_no_such_frame(handler, code): with pytest.raises(exceptions.NoSuchFrameException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.UNKNOWN_COMMAND) def test_raises_exception_for_unknown_command(handler, code): with pytest.raises(exceptions.WebDriverException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.STALE_ELEMENT_REFERENCE) def test_raises_exception_for_stale_element_reference(handler, code): with pytest.raises(exceptions.StaleElementReferenceException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.ELEMENT_NOT_VISIBLE) def test_raises_exception_for_element_not_visible(handler, code): with pytest.raises(exceptions.ElementNotVisibleException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.INVALID_ELEMENT_STATE) def test_raises_exception_for_invalid_element_state(handler, code): with pytest.raises(exceptions.InvalidElementStateException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.UNKNOWN_ERROR) def test_raises_exception_for_unknown_error(handler, code): with pytest.raises(exceptions.WebDriverException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.ELEMENT_IS_NOT_SELECTABLE) def test_raises_exception_for_element_not_selectable(handler, code): with pytest.raises(exceptions.ElementNotSelectableException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.JAVASCRIPT_ERROR) def test_raises_exception_for_javascript_error(handler, code): with pytest.raises(exceptions.JavascriptException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.XPATH_LOOKUP_ERROR) def test_raises_exception_for_xpath_lookup_error(handler, code): with pytest.raises(exceptions.WebDriverException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.TIMEOUT) def test_raises_exception_for_timeout(handler, code): with pytest.raises(exceptions.TimeoutException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.NO_SUCH_WINDOW) def test_raises_exception_for_no_such_window(handler, code): with pytest.raises(exceptions.NoSuchWindowException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.INVALID_COOKIE_DOMAIN) def test_raises_exception_for_invalid_cookie_domain(handler, code): with pytest.raises(exceptions.InvalidCookieDomainException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.UNABLE_TO_SET_COOKIE) def test_raises_exception_for_unable_to_set_cookie(handler, code): with pytest.raises(exceptions.UnableToSetCookieException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.UNEXPECTED_ALERT_OPEN) def test_raises_exception_for_unexpected_alert_open(handler, code): with pytest.raises(exceptions.UnexpectedAlertPresentException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.NO_ALERT_OPEN) def test_raises_exception_for_no_alert_open(handler, code): with pytest.raises(exceptions.NoAlertPresentException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.SCRIPT_TIMEOUT) def test_raises_exception_for_script_timeout(handler, code): with pytest.raises(exceptions.TimeoutException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.INVALID_ELEMENT_COORDINATES) def test_raises_exception_for_invalid_element_coordinates(handler, code): with pytest.raises(exceptions.WebDriverException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.IME_NOT_AVAILABLE) def test_raises_exception_for_ime_not_available(handler, code): with pytest.raises(exceptions.ImeNotAvailableException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.IME_ENGINE_ACTIVATION_FAILED) def test_raises_exception_for_ime_activation_failed(handler, code): with pytest.raises(exceptions.ImeActivationFailedException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.INVALID_SELECTOR) def test_raises_exception_for_invalid_selector(handler, code): with pytest.raises(exceptions.InvalidSelectorException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.SESSION_NOT_CREATED) def test_raises_exception_for_session_not_created(handler, code): with pytest.raises(exceptions.SessionNotCreatedException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.MOVE_TARGET_OUT_OF_BOUNDS) def test_raises_exception_for_move_target_out_of_bounds(handler, code): with pytest.raises(exceptions.MoveTargetOutOfBoundsException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.INVALID_XPATH_SELECTOR) def test_raises_exception_for_invalid_xpath_selector(handler, code): with pytest.raises(exceptions.InvalidSelectorException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.INVALID_XPATH_SELECTOR_RETURN_TYPER) def test_raises_exception_for_invalid_xpath_selector_return_typer(handler, code): with pytest.raises(exceptions.InvalidSelectorException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.ELEMENT_NOT_INTERACTABLE) def test_raises_exception_for_element_not_interactable(handler, code): with pytest.raises(exceptions.ElementNotInteractableException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.INSECURE_CERTIFICATE) def test_raises_exception_for_insecure_certificate(handler, code): with pytest.raises(exceptions.InsecureCertificateException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.INVALID_ARGUMENT) def test_raises_exception_for_invalid_argument(handler, code): with pytest.raises(exceptions.InvalidArgumentException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.INVALID_COORDINATES) def test_raises_exception_for_invalid_coordinates(handler, code): with pytest.raises(exceptions.InvalidCoordinatesException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.INVALID_SESSION_ID) def test_raises_exception_for_invalid_session_id(handler, code): with pytest.raises(exceptions.InvalidSessionIdException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.NO_SUCH_COOKIE) def test_raises_exception_for_no_such_cookie(handler, code): with pytest.raises(exceptions.NoSuchCookieException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.UNABLE_TO_CAPTURE_SCREEN) def test_raises_exception_for_unable_to_capture_screen_exception(handler, code): with pytest.raises(exceptions.ScreenshotException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.ELEMENT_CLICK_INTERCEPTED) def test_raises_exception_for_element_click_intercepted(handler, code): with pytest.raises(exceptions.ElementClickInterceptedException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.UNKNOWN_METHOD) def test_raises_exception_for_unknown_method(handler, code): with pytest.raises(exceptions.UnknownMethodException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.METHOD_NOT_ALLOWED) def test_raises_exception_for_method_not_allowed(handler, code): with pytest.raises(exceptions.WebDriverException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("key", ["stackTrace", "stacktrace"]) def test_relays_exception_stacktrace(handler, key): import json stacktrace = {"lineNumber": 100, "fileName": "egg", "methodName": "ham", "className": "Spam"} value = {key: [stacktrace], "message": "very bad", "error": ErrorCode.UNKNOWN_METHOD[0]} response = {"status": 400, "value": json.dumps({"value": value})} with pytest.raises(exceptions.UnknownMethodException) as e: handler.check_response(response) assert "Spam.ham" in e.value.stacktrace[0] def test_handle_errors_better(handler): import json response = { "status": 500, "value": json.dumps( { "value": { "message": "Could not start a new session. No Node supports the required capabilities: Capabilities {browserName: chrome, goog:chromeOptions: {args: [headless, silent], extensions: [], w3c: false}}, Capabilities {browserName: chrome, goog:chromeOptions: {args: [headless, silent], extensions: [], w3c: false}, version: }\nBuild info: version: '4.0.0-beta-3', revision: '5d108f9a67'\nSystem info: host: '9315f0a993d2', ip: '172.17.0.8', os.name: 'Linux', os.arch: 'amd64', os.version: '5.8.0-44-generic', java.version: '1.8.0_282'\nDriver info: driver.version: unknown" } } ), } with pytest.raises(exceptions.WebDriverException) as e: handler.check_response(response) assert "Could not start a new session." in e.value.msg selenium-selenium-4.23.0/test/unit/selenium/webdriver/remote/__init__.py0000664000175000017500000000142314646203155026304 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.23.0/test/unit/selenium/webdriver/remote/subtyping_tests.py0000664000175000017500000000417514646203155030022 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from selenium.webdriver.remote.webdriver import WebDriver from selenium.webdriver.remote.webdriver import WebElement def test_web_element_not_subclassed(): """A registered subtype of WebElement should work with isinstance checks.""" class MyWebElement: def __init__(self, parent, id, _w3c=True): self.parent = parent self.id = id self._w3c = _w3c # Test that non registered class instance is not instance of Remote WebElement my_web_element = MyWebElement("parent", "1") assert not isinstance(my_web_element, WebElement) # Register the class as a subtype of WebElement WebElement.register(MyWebElement) my_registered_web_element = MyWebElement("parent", "2") assert isinstance(my_registered_web_element, WebElement) def test_webdriver_not_subclassed(): """A registered subtype of WebDriver should work with isinstance checks.""" class MyWebDriver: def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Test that non registered class instance is not instance of Remote WebDriver my_driver = MyWebDriver() assert not isinstance(my_driver, WebDriver) # Register the class as a subtype of WebDriver WebDriver.register(MyWebDriver) my_registered_driver = MyWebDriver() assert isinstance(my_registered_driver, MyWebDriver) selenium-selenium-4.23.0/test/unit/selenium/webdriver/remote/remote_connection_tests.py0000664000175000017500000002235514646203155031510 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from urllib import parse import pytest import urllib3 from selenium import __version__ from selenium.webdriver.remote.remote_connection import RemoteConnection def test_get_remote_connection_headers_defaults(): url = "http://remote" headers = RemoteConnection.get_remote_connection_headers(parse.urlparse(url)) assert "Authorization" not in headers assert "Connection" not in headers assert headers.get("Accept") == "application/json" assert headers.get("Content-Type") == "application/json;charset=UTF-8" assert headers.get("User-Agent").startswith(f"selenium/{__version__} (python ") assert headers.get("User-Agent").split(" ")[-1] in {"windows)", "mac)", "linux)"} def test_get_remote_connection_headers_adds_auth_header_if_pass(): url = "http://user:pass@remote" headers = RemoteConnection.get_remote_connection_headers(parse.urlparse(url)) assert headers.get("Authorization") == "Basic dXNlcjpwYXNz" def test_get_remote_connection_headers_adds_keep_alive_if_requested(): url = "http://remote" headers = RemoteConnection.get_remote_connection_headers(parse.urlparse(url), keep_alive=True) assert headers.get("Connection") == "keep-alive" def test_get_proxy_url_http(mock_proxy_settings): proxy = "http://http_proxy.com:8080" remote_connection = RemoteConnection("http://remote", keep_alive=False) proxy_url = remote_connection._get_proxy_url() assert proxy_url == proxy def test_get_proxy_url_https(mock_proxy_settings): proxy = "http://https_proxy.com:8080" remote_connection = RemoteConnection("https://remote", keep_alive=False) proxy_url = remote_connection._get_proxy_url() assert proxy_url == proxy def test_get_proxy_url_none(mock_proxy_settings_missing): remote_connection = RemoteConnection("https://remote", keep_alive=False) proxy_url = remote_connection._get_proxy_url() assert proxy_url is None def test_get_proxy_url_http_auth(mock_proxy_auth_settings): remote_connection = RemoteConnection("http://remote", keep_alive=False) proxy_url = remote_connection._get_proxy_url() raw_proxy_url, basic_auth_string = remote_connection._separate_http_proxy_auth() assert proxy_url == "http://user:password@http_proxy.com:8080" assert raw_proxy_url == "http://http_proxy.com:8080" assert basic_auth_string == "user:password" def test_get_proxy_url_https_auth(mock_proxy_auth_settings): remote_connection = RemoteConnection("https://remote", keep_alive=False) proxy_url = remote_connection._get_proxy_url() raw_proxy_url, basic_auth_string = remote_connection._separate_http_proxy_auth() assert proxy_url == "https://user:password@https_proxy.com:8080" assert raw_proxy_url == "https://https_proxy.com:8080" assert basic_auth_string == "user:password" def test_get_connection_manager_without_proxy(mock_proxy_settings_missing): remote_connection = RemoteConnection("http://remote", keep_alive=False) conn = remote_connection._get_connection_manager() assert isinstance(conn, urllib3.PoolManager) def test_get_connection_manager_for_certs_and_timeout(monkeypatch): monkeypatch.setattr(RemoteConnection, "get_timeout", lambda _: 10) # Class state; leaks into subsequent tests. remote_connection = RemoteConnection("http://remote", keep_alive=False) conn = remote_connection._get_connection_manager() assert conn.connection_pool_kw["timeout"] == 10 assert conn.connection_pool_kw["cert_reqs"] == "CERT_REQUIRED" assert "certifi/cacert.pem" in conn.connection_pool_kw["ca_certs"] def test_default_socket_timeout_is_correct(): remote_connection = RemoteConnection("http://remote", keep_alive=True) conn = remote_connection._get_connection_manager() assert conn.connection_pool_kw["timeout"] is None def test_get_connection_manager_with_proxy(mock_proxy_settings): remote_connection = RemoteConnection("http://remote", keep_alive=False) conn = remote_connection._get_connection_manager() assert isinstance(conn, urllib3.ProxyManager) assert conn.proxy.scheme == "http" assert conn.proxy.host == "http_proxy.com" assert conn.proxy.port == 8080 remote_connection_https = RemoteConnection("https://remote", keep_alive=False) conn = remote_connection_https._get_connection_manager() assert isinstance(conn, urllib3.ProxyManager) assert conn.proxy.scheme == "http" assert conn.proxy.host == "https_proxy.com" assert conn.proxy.port == 8080 def test_get_connection_manager_with_auth_proxy(mock_proxy_auth_settings): proxy_auth_header = urllib3.make_headers(proxy_basic_auth="user:password") remote_connection = RemoteConnection("http://remote", keep_alive=False) conn = remote_connection._get_connection_manager() assert isinstance(conn, urllib3.ProxyManager) assert conn.proxy.scheme == "http" assert conn.proxy.host == "http_proxy.com" assert conn.proxy.port == 8080 assert conn.proxy_headers == proxy_auth_header remote_connection_https = RemoteConnection("https://remote", keep_alive=False) conn = remote_connection_https._get_connection_manager() assert isinstance(conn, urllib3.ProxyManager) assert conn.proxy.scheme == "https" assert conn.proxy.host == "https_proxy.com" assert conn.proxy.port == 8080 assert conn.proxy_headers == proxy_auth_header @pytest.mark.parametrize( "url", [ "*", ".localhost", "localhost:80", "locahost", "127.0.0.1", "LOCALHOST", "LOCALHOST:80", "http://localhost", "https://localhost", "test.localhost", " localhost", "::1", "127.0.0.2", ], ) def test_get_connection_manager_when_no_proxy_set(mock_no_proxy_settings, url): remote_connection = RemoteConnection(url) conn = remote_connection._get_connection_manager() assert isinstance(conn, urllib3.PoolManager) def test_ignore_proxy_env_vars(mock_proxy_settings): remote_connection = RemoteConnection("http://remote", ignore_proxy=True) conn = remote_connection._get_connection_manager() assert isinstance(conn, urllib3.PoolManager) def test_get_socks_proxy_when_set(mock_socks_proxy_settings): remote_connection = RemoteConnection("http://127.0.0.1:4444/wd/hub") conn = remote_connection._get_connection_manager() from urllib3.contrib.socks import SOCKSProxyManager assert isinstance(conn, SOCKSProxyManager) class MockResponse: code = 200 headers = [] def read(self): return b"{}" def close(self): pass def getheader(self, *args, **kwargs): pass @pytest.fixture(scope="function") def mock_proxy_settings_missing(monkeypatch): monkeypatch.delenv("HTTPS_PROXY", raising=False) monkeypatch.delenv("HTTP_PROXY", raising=False) monkeypatch.delenv("https_proxy", raising=False) monkeypatch.delenv("http_proxy", raising=False) @pytest.fixture(scope="function") def mock_socks_proxy_settings(monkeypatch): http_proxy = "SOCKS5://http_proxy.com:8080" https_proxy = "SOCKS5://https_proxy.com:8080" monkeypatch.setenv("HTTPS_PROXY", https_proxy) monkeypatch.setenv("HTTP_PROXY", http_proxy) monkeypatch.setenv("https_proxy", https_proxy) monkeypatch.setenv("http_proxy", http_proxy) @pytest.fixture(scope="function") def mock_proxy_settings(monkeypatch): http_proxy = "http://http_proxy.com:8080" https_proxy = "http://https_proxy.com:8080" monkeypatch.setenv("HTTPS_PROXY", https_proxy) monkeypatch.setenv("HTTP_PROXY", http_proxy) monkeypatch.setenv("https_proxy", https_proxy) monkeypatch.setenv("http_proxy", http_proxy) @pytest.fixture(scope="function") def mock_proxy_auth_settings(monkeypatch): http_proxy = "http://user:password@http_proxy.com:8080" https_proxy = "https://user:password@https_proxy.com:8080" monkeypatch.setenv("HTTPS_PROXY", https_proxy) monkeypatch.setenv("HTTP_PROXY", http_proxy) monkeypatch.setenv("https_proxy", https_proxy) monkeypatch.setenv("http_proxy", http_proxy) @pytest.fixture(scope="function") def mock_no_proxy_settings(monkeypatch): http_proxy = "http://http_proxy.com:8080" https_proxy = "http://https_proxy.com:8080" monkeypatch.setenv("HTTPS_PROXY", https_proxy) monkeypatch.setenv("HTTP_PROXY", http_proxy) monkeypatch.setenv("https_proxy", https_proxy) monkeypatch.setenv("http_proxy", http_proxy) monkeypatch.setenv("no_proxy", "65.253.214.253,localhost,127.0.0.1,*zyz.xx,::1") monkeypatch.setenv("NO_PROXY", "65.253.214.253,localhost,127.0.0.1,*zyz.xx,::1,127.0.0.0/8") selenium-selenium-4.23.0/test/unit/selenium/webdriver/remote/new_session_tests.py0000664000175000017500000001046114646203155030325 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from importlib import import_module import pytest from selenium.webdriver.chrome.options import Options as ChromeOptions from selenium.webdriver.common.options import ArgOptions from selenium.webdriver.common.options import PageLoadStrategy from selenium.webdriver.common.proxy import Proxy from selenium.webdriver.common.proxy import ProxyType from selenium.webdriver.remote import webdriver from selenium.webdriver.remote.command import Command from selenium.webdriver.remote.webdriver import WebDriver def test_converts_proxy_type_value_to_lowercase_for_w3c(mocker): mock = mocker.patch("selenium.webdriver.remote.webdriver.WebDriver.execute") w3c_caps = {"pageLoadStrategy": "normal", "proxy": {"proxyType": "manual", "httpProxy": "foo"}} options = ArgOptions() proxy = Proxy({"proxyType": ProxyType.MANUAL, "httpProxy": "foo"}) options.proxy = proxy WebDriver(options=options) expected_params = {"capabilities": {"firstMatch": [{}], "alwaysMatch": w3c_caps}} mock.assert_called_with(Command.NEW_SESSION, expected_params) def test_works_as_context_manager(mocker): mocker.patch("selenium.webdriver.remote.webdriver.WebDriver.execute") quit_ = mocker.patch("selenium.webdriver.remote.webdriver.WebDriver.quit") with WebDriver(options=ChromeOptions()) as driver: assert isinstance(driver, WebDriver) assert quit_.call_count == 1 @pytest.mark.parametrize("browser_name", ["firefox", "chrome", "ie"]) def test_acepts_options_to_remote_driver(mocker, browser_name): options = import_module(f"selenium.webdriver.{browser_name}.options") mock = mocker.patch("selenium.webdriver.remote.webdriver.WebDriver.start_session") opts = options.Options() opts.add_argument("foo") WebDriver(options=opts) expected_caps = opts.to_capabilities() mock.assert_called_with(expected_caps) def test_always_match_if_2_of_the_same_options(): from selenium.webdriver.chrome.options import Options as ChromeOptions from selenium.webdriver.chrome.options import Options as ChromeOptions2 co1 = ChromeOptions() co1.add_argument("foo") co2 = ChromeOptions2() co2.add_argument("bar") expected = { "capabilities": { "alwaysMatch": { "browserName": "chrome", "pageLoadStrategy": PageLoadStrategy.normal, }, "firstMatch": [ {"goog:chromeOptions": {"args": ["foo"], "extensions": []}}, {"goog:chromeOptions": {"args": ["bar"], "extensions": []}}, ], } } result = webdriver.create_matches([co1, co2]) assert expected == result def test_first_match_when_2_different_option_types(): from selenium.webdriver.chrome.options import Options as ChromeOptions from selenium.webdriver.firefox.options import Options as FirefoxOptions expected = { "capabilities": { "alwaysMatch": {"pageLoadStrategy": PageLoadStrategy.normal}, "firstMatch": [ {"browserName": "chrome", "goog:chromeOptions": {"extensions": [], "args": []}}, { "browserName": "firefox", "acceptInsecureCerts": True, "moz:debuggerAddress": True, "moz:firefoxOptions": {"args": ["foo"], "prefs": {"remote.active-protocols": 3}}, }, ], } } firefox_options = FirefoxOptions() firefox_options.add_argument("foo") result = webdriver.create_matches([ChromeOptions(), firefox_options]) assert expected == result selenium-selenium-4.23.0/test/unit/selenium/webdriver/__init__.py0000664000175000017500000000142314646203155025011 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.23.0/test/unit/selenium/webdriver/chrome/0000775000175000017500000000000014646203155024155 5ustar carstencarstenselenium-selenium-4.23.0/test/unit/selenium/webdriver/chrome/chrome_options_tests.py0000664000175000017500000001102514646203155031000 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import platform from os import path import pytest from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.options import PageLoadStrategy @pytest.fixture def options(): return Options() def test_set_binary_location(options): options.binary_location = "/foo/bar" assert options._binary_location == "/foo/bar" def test_get_binary_location(options): options._binary_location = "/foo/bar" assert options.binary_location == "/foo/bar" def test_set_debugger_address(options): options.debugger_address = "/foo/bar" assert options._debugger_address == "/foo/bar" def test_get_debugger_address(options): options._debugger_address = "/foo/bar" assert options.debugger_address == "/foo/bar" def test_add_arguments(options): options.add_argument("foo") assert "foo" in options._arguments def test_get_arguments(options): options._arguments = ["foo"] assert "foo" in options.arguments def test_raises_exception_if_argument_is_falsy(options): with pytest.raises(ValueError): options.add_argument(None) def test_raises_exception_if_extension_is_falsy(options): with pytest.raises(ValueError): options.add_extension(None) def test_raises_exception_if_extension_does_not_exist(options): with pytest.raises(IOError): options.add_extension(path.join(path.abspath(path.curdir), "fakepath")) def test_add_extension(options, mocker): pth = path.abspath(path.expanduser("/foo/bar")) mocker.patch("os.path.exists").return_value = True options.add_extension(pth) assert pth in options._extension_files def test_raises_exception_if_encoded_extension_is_falsy(options): with pytest.raises(ValueError): options.add_encoded_extension(None) def test_add_encoded_extension(options): options.add_encoded_extension("/foo/bar") assert "/foo/bar" in options._extensions def test_get_extensions_from_extension_files(options, mocker): null = "NUL" if platform.system().lower() == "windows" else "/dev/null" mocker.patch("selenium.webdriver.chromium.options.open").return_value = open(null) mocker.patch("base64.b64encode").return_value = b"foo" options._extension_files = ["foo"] assert "foo" in options.extensions def test_get_extensions_from_encoded_extensions(options, mocker): options._extensions = ["foo"] assert "foo" in options.extensions def test_add_experimental_options(options): options.add_experimental_option("foo", "bar") assert options._experimental_options["foo"] == "bar" def test_get_experimental_options(options): options._experimental_options = {"foo": "bar"} assert options.experimental_options["foo"] == "bar" def test_creates_capabilities(options): options._arguments = ["foo"] options._binary_location = "/bar" options._extensions = ["baz"] options._debugger_address = "/foo/bar" options._experimental_options = {"foo": "bar"} caps = options.to_capabilities() opts = caps.get(Options.KEY) assert opts assert "foo" in opts["args"] assert opts["binary"] == "/bar" assert "baz" in opts["extensions"] assert opts["debuggerAddress"] == "/foo/bar" assert opts["foo"] == "bar" def test_starts_with_default_capabilities(options): from selenium.webdriver import DesiredCapabilities caps = DesiredCapabilities.CHROME.copy() caps.update({"pageLoadStrategy": PageLoadStrategy.normal}) assert options._caps == caps def test_is_a_baseoptions(options): from selenium.webdriver.common.options import BaseOptions assert isinstance(options, BaseOptions) def test_enables_chrome_mobile(options): options.enable_mobile() result_caps = options.to_capabilities() assert result_caps["goog:chromeOptions"]["androidPackage"] == "com.android.chrome" selenium-selenium-4.23.0/test/unit/selenium/webdriver/ie/0000775000175000017500000000000014646203155023275 5ustar carstencarstenselenium-selenium-4.23.0/test/unit/selenium/webdriver/ie/__init__.py0000664000175000017500000000142314646203155025406 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.23.0/test/unit/selenium/webdriver/ie/test_ie_options.py0000664000175000017500000001453614646203155027067 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.options import PageLoadStrategy from selenium.webdriver.ie.options import ElementScrollBehavior from selenium.webdriver.ie.options import Options TIMEOUT = 30 @pytest.fixture def opts(): yield Options() def test_arguments(opts): arg1 = "-k" arg2 = "-private" opts.add_argument(arg1) opts.add_argument(arg2) assert arg1 in opts.arguments assert arg2 in opts.arguments def test_browser_attach_timeout(opts): opts.browser_attach_timeout = TIMEOUT assert opts.browser_attach_timeout == TIMEOUT assert opts.options.get(Options.BROWSER_ATTACH_TIMEOUT) == TIMEOUT def test_raises_exception_for_invalid_browser_attach_timeout(opts): with pytest.raises(ValueError): opts.browser_attach_timeout = "foo" def test_element_scroll_behavior(opts): opts.element_scroll_behavior = ElementScrollBehavior.BOTTOM assert opts.element_scroll_behavior == ElementScrollBehavior.BOTTOM assert opts.options.get(Options.ELEMENT_SCROLL_BEHAVIOR) == ElementScrollBehavior.BOTTOM def test_ensure_clean_session(opts): opts.ensure_clean_session = True assert opts.ensure_clean_session is True assert opts.options.get(Options.ENSURE_CLEAN_SESSION) is True def test_file_upload_dialog_timeout(opts): opts.file_upload_dialog_timeout = TIMEOUT assert opts.file_upload_dialog_timeout is TIMEOUT assert opts.options.get(Options.FILE_UPLOAD_DIALOG_TIMEOUT) is TIMEOUT def test_raises_exception_for_file_upload_dialog_timeout(opts): with pytest.raises(ValueError): opts.file_upload_dialog_timeout = "foo" def test_force_create_process_api(opts): opts.force_create_process_api = True assert opts.force_create_process_api is True assert opts.options.get(Options.FORCE_CREATE_PROCESS_API) is True def test_force_shell_windows_api(opts): opts.force_shell_windows_api = True assert opts.force_shell_windows_api is True assert opts.options.get(Options.FORCE_SHELL_WINDOWS_API) is True def test_full_page_screenshot(opts): opts.full_page_screenshot = True assert opts.full_page_screenshot is True assert opts.options.get(Options.FULL_PAGE_SCREENSHOT) is True def test_ignore_protected_mode_settings(opts): opts.ignore_protected_mode_settings = True assert opts.ignore_protected_mode_settings is True assert opts.options.get(Options.IGNORE_PROTECTED_MODE_SETTINGS) is True def test_ignore_zoom_level(opts): opts.ignore_zoom_level = True assert opts.ignore_zoom_level is True assert opts.options.get(Options.IGNORE_ZOOM_LEVEL) is True def test_initial_browser_url(opts): url = "http://www.selenium.dev" opts.initial_browser_url = url assert opts.initial_browser_url == url assert opts.options.get(Options.INITIAL_BROWSER_URL) == url def test_native_events(opts): opts.native_events = True assert opts.native_events is True assert opts.options.get(Options.NATIVE_EVENTS) is True def test_persistent_hover(opts): opts.persistent_hover = True assert opts.persistent_hover is True assert opts.options.get(Options.PERSISTENT_HOVER) is True def test_require_window_focus(opts): opts.require_window_focus = True assert opts.require_window_focus is True assert opts.options.get(Options.REQUIRE_WINDOW_FOCUS) is True def test_use_per_process_proxy(opts): opts.use_per_process_proxy = True assert opts.use_per_process_proxy is True assert opts.options.get(Options.USE_PER_PROCESS_PROXY) is True def test_use_legacy_file_upload_dialog_handling(opts): opts.use_legacy_file_upload_dialog_handling = True assert opts.use_legacy_file_upload_dialog_handling is True assert opts.options.get(Options.USE_LEGACY_FILE_UPLOAD_DIALOG_HANDLING) is True def test_attach_to_edge_chrome(opts): opts.attach_to_edge_chrome = True assert opts.attach_to_edge_chrome is True assert opts.options.get(Options.ATTACH_TO_EDGE_CHROME) is True def test_edge_executable_path(opts): path = "/path/to/edge" opts.edge_executable_path = path assert opts.edge_executable_path == path assert opts.options.get(Options.EDGE_EXECUTABLE_PATH) == path def test_additional_options(opts): opts.add_additional_option("foo", "bar") assert opts.additional_options.get("foo") == "bar" def test_to_capabilities(opts): opts._options["foo"] = "bar" assert Options.KEY in opts.to_capabilities() assert opts.to_capabilities().get(Options.KEY) == opts._options def test_to_capabilities_arguments(opts): arg = "-k" opts.add_argument(arg) caps_opts = opts.to_capabilities().get(Options.KEY) assert caps_opts.get(Options.SWITCHES) == arg def test_to_capabilities_additional_options(opts): name = "foo" value = "bar" opts.add_additional_option(name, value) caps_opts = opts.to_capabilities().get(Options.KEY) assert caps_opts.get(name) == value def test_to_capabilities_should_not_modify_set_options(opts): opts._options["foo"] = "bar" arg = "-k" opts.add_argument(arg) opts.add_additional_option("baz", "qux") opts.to_capabilities().get(Options.KEY) assert opts.options.get("foo") == "bar" assert opts.arguments[0] == arg assert opts.additional_options.get("baz") == "qux" def test_starts_with_default_capabilities(opts): from selenium.webdriver import DesiredCapabilities caps = DesiredCapabilities.INTERNETEXPLORER.copy() caps.update({"pageLoadStrategy": PageLoadStrategy.normal}) assert opts._caps == caps def test_is_a_baseoptions(opts): from selenium.webdriver.common.options import BaseOptions assert isinstance(opts, BaseOptions) selenium-selenium-4.23.0/test/unit/selenium/webdriver/safari/0000775000175000017500000000000014646203155024145 5ustar carstencarstenselenium-selenium-4.23.0/test/unit/selenium/webdriver/safari/safari_options_tests.py0000664000175000017500000000433514646203155030766 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.options import PageLoadStrategy from selenium.webdriver.safari.options import Options @pytest.fixture def options(): return Options() def test_starts_with_default_capabilities(options): from selenium.webdriver import DesiredCapabilities caps = DesiredCapabilities.SAFARI.copy() caps.update({"pageLoadStrategy": PageLoadStrategy.normal}) assert options._caps == caps def test_is_a_baseoptions(options): from selenium.webdriver.common.options import BaseOptions assert isinstance(options, BaseOptions) def test_can_set_automatic_inspection(options): options.automatic_inspection = True assert options.automatic_inspection is True assert options._caps.get(Options.AUTOMATIC_INSPECTION) is True def test_can_set_automatic_profiling(options): options.automatic_profiling = True assert options.automatic_profiling is True assert options._caps.get(Options.AUTOMATIC_PROFILING) is True def test_setting_technology_preview_changes_browser_name(options): from selenium.webdriver import DesiredCapabilities BROWSER_NAME = "browserName" assert options._caps.get(BROWSER_NAME) == DesiredCapabilities.SAFARI[BROWSER_NAME] options.use_technology_preview = True assert options._caps.get(BROWSER_NAME) == options.SAFARI_TECH_PREVIEW options.use_technology_preview = False assert options._caps.get(BROWSER_NAME) == DesiredCapabilities.SAFARI[BROWSER_NAME] selenium-selenium-4.23.0/test/unit/selenium/webdriver/common/0000775000175000017500000000000014646203155024170 5ustar carstencarstenselenium-selenium-4.23.0/test/unit/selenium/webdriver/common/common_options_tests.py0000664000175000017500000000603614646203155031034 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver import Proxy from selenium.webdriver.common.options import ArgOptions from selenium.webdriver.common.proxy import ProxyType @pytest.fixture def options(): return ArgOptions() def test_add_arguments(options): options.add_argument("foo") assert "foo" in options._arguments def test_get_arguments(options): options._arguments = ["foo"] assert "foo" in options.arguments def test_enables_mobile(options): options.enable_mobile(android_package="cheese") assert options.mobile_options["androidPackage"] == "cheese" assert not hasattr(options.mobile_options, "androidActivity") assert not hasattr(options.mobile_options, "androidDeviceSerial") def test_enable_mobile_errors_without_package(options): with pytest.raises(AttributeError): options.enable_mobile() def test_enable_mobile_with_activity(options): options.enable_mobile(android_package="sausages", android_activity="eating") assert options.mobile_options["androidActivity"] == "eating" def test_enable_mobile_with_device_serial(options): options.enable_mobile(android_package="cheese", android_activity="crackers", device_serial="1234") options.mobile_options["androidDeviceSerial"] == "1234" def test_missing_capabilities_return_false_rather_than_none(): options = ArgOptions() assert options.strict_file_interactability is False assert options.set_window_rect is False assert options.accept_insecure_certs is False def test_add_proxy(): options = ArgOptions() proxy = Proxy({"proxyType": ProxyType.MANUAL}) proxy.http_proxy = "http://user:password@http_proxy.com:8080" options.proxy = proxy caps = options.to_capabilities() assert options.proxy == proxy assert caps.get("proxy") == proxy.to_capabilities() def test_default_bidi(): options = ArgOptions() assert options.enable_bidi is False assert options.web_socket_url is None def test_enable_bidi(): options = ArgOptions() options.enable_bidi = True assert options.enable_bidi is True assert options.web_socket_url is None def test_set_socket_url(): options = ArgOptions() options.web_socket_url = "socket_url" assert options.enable_bidi is True assert options.web_socket_url == "socket_url" selenium-selenium-4.23.0/test/unit/selenium/webdriver/common/cdp_module_fallback_tests.py0000664000175000017500000000237314646203155031723 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import logging import re import types from selenium.webdriver.common.bidi.cdp import import_devtools def test_missing_cdp_devtools_version_falls_back(caplog): with caplog.at_level(logging.DEBUG, logger="selenium"): assert isinstance(import_devtools("will_never_exist"), types.ModuleType) # assert the fallback occurred successfully offered up a v{n} option. assert re.match(r"Falling back to loading `devtools`: v\d+", caplog.records[-1].getMessage()) is not None selenium-selenium-4.23.0/test/unit/selenium/webdriver/common/print_page_options_tests.py0000664000175000017500000000622514646203155031674 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.print_page_options import PrintOptions @pytest.fixture def print_options(): return PrintOptions() def test_set_orientation(print_options): print_options.orientation = "portrait" assert print_options.orientation == "portrait" def test_raises_exception_if_orientation_is_invalid(print_options): with pytest.raises(ValueError): print_options.orientation = "foobar" def test_set_scale(print_options): print_options.scale = 1 assert print_options.scale == 1 def test_raises_exception_if_scale_is_outside_range(print_options): with pytest.raises(ValueError): print_options.scale = 3 def test_raises_exception_if_scale_is_not_an_integer(print_options): with pytest.raises(ValueError): print_options.scale = "1" def test_set_background(print_options): print_options.background = True assert print_options.background is True def test_unset_value_to_be_none(print_options): assert print_options.page_width is None def test_set_width(print_options): print_options.page_width = 3 assert print_options.page_width == 3 def test_raises_exception_if_set_invalid_width(print_options): with pytest.raises(ValueError): print_options.page_width = -1 def test_raises_exception_if_set_with_not_int(print_options): with pytest.raises(ValueError): print_options.page_width = "2" def test_set_height(print_options): print_options.page_height = 2 assert print_options.page_height == 2 def test_set_shrink_to_fit(print_options): print_options.shrink_to_fit = True assert print_options.shrink_to_fit is True def test_raises_exception_if_set_shrink_to_fit_non_bool(print_options): with pytest.raises(ValueError): print_options.shrink_to_fit = "True" def test_set_page_ranges(print_options): print_options.page_ranges = ["1-2"] assert print_options.page_ranges == ["1-2"] def test_raises_exception_if_page_ranges_not_list(print_options): with pytest.raises(ValueError): print_options.page_ranges = "foobar" def test_margin_height(print_options): print_options.margin_top = 2 assert print_options.margin_top == 2 def test_raises_exception_if_margin_is_invalid(print_options): with pytest.raises(ValueError): print_options.margin_top = -1 with pytest.raises(ValueError): print_options.margin_top = "2" selenium-selenium-4.23.0/test/unit/selenium/webdriver/virtual_authenticator/0000775000175000017500000000000014646203155027320 5ustar carstencarstenselenium-selenium-4.23.0/test/unit/selenium/webdriver/virtual_authenticator/__init__.py0000664000175000017500000000142314646203155031431 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. ././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootselenium-selenium-4.23.0/test/unit/selenium/webdriver/virtual_authenticator/virtual_authenticator_options_tests.pyselenium-selenium-4.23.0/test/unit/selenium/webdriver/virtual_authenticator/virtual_authenticator_op0000664000175000017500000000364714646203155034373 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.virtual_authenticator import VirtualAuthenticatorOptions @pytest.fixture def options(): return VirtualAuthenticatorOptions() def test_bespoke_options_for_virtual_authenticator(): assert VirtualAuthenticatorOptions( protocol="ctap1/u2f", transport="ble", has_resident_key=True, has_user_verification=True, is_user_consenting=False, is_user_verified=True, ).to_dict() == { "protocol": "ctap1/u2f", "transport": "ble", "hasResidentKey": True, "hasUserVerification": True, "isUserConsenting": False, "isUserVerified": True, } def test_to_dict_with_defaults(options): default_options = options.to_dict() assert default_options["transport"] == VirtualAuthenticatorOptions.Transport.USB.value assert default_options["protocol"] == VirtualAuthenticatorOptions.Protocol.CTAP2.value assert default_options["hasResidentKey"] is False assert default_options["hasUserVerification"] is False assert default_options["isUserConsenting"] is True assert default_options["isUserVerified"] is False selenium-selenium-4.23.0/test/unit/selenium/webdriver/virtual_authenticator/credentials_test.py0000664000175000017500000001303214646203155033225 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from base64 import urlsafe_b64decode from base64 import urlsafe_b64encode from typing import Tuple import pytest from selenium.webdriver.common.virtual_authenticator import Credential BASE64__ENCODED_PK = """ MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDbBOu5Lhs4vpowbCnmCyLUpIE7JM9sm9QXzye2G+jr+Kr MsinWohEce47BFPJlTaDzHSvOW2eeunBO89ZcvvVc8RLz4qyQ8rO98xS1jtgqi1NcBPETDrtzthODu/gd0sjB2Tk3TLuBGV oPXt54a+Oo4JbBJ6h3s0+5eAfGplCbSNq6hN3Jh9YOTw5ZA6GCEy5l8zBaOgjXytd2v2OdSVoEDNiNQRkjJd2rmS2oi9AyQ FR3B7BrPSiDlCcITZFOWgLF5C31Wp/PSHwQhlnh7/6YhnE2y9tzsUvzx0wJXrBADW13+oMxrneDK3WGbxTNYgIi1PvSqXlq GjHtCK+R2QkXAgMBAAECggEAVc6bu7VAnP6v0gDOeX4razv4FX/adCao9ZsHZ+WPX8PQxtmWYqykH5CY4TSfsuizAgyPuQ0 +j4Vjssr9VODLqFoanspT6YXsvaKanncUYbasNgUJnfnLnw3an2XpU2XdmXTNYckCPRX9nsAAURWT3/n9ljc/XYY22ecYxM 8sDWnHu2uKZ1B7M3X60bQYL5T/lVXkKdD6xgSNLeP4AkRx0H4egaop68hoW8FIwmDPVWYVAvo8etzWCtibRXz5FcNld9MgD /Ai7ycKy4Q1KhX5GBFI79MVVaHkSQfxPHpr7/XcmpQOEAr+BMPon4s4vnKqAGdGB3j/E3d/+4F2swykoQKBgQD8hCsp6FIQ 5umJlk9/j/nGsMl85LgLaNVYpWlPRKPc54YNumtvj5vx1BG+zMbT7qIE3nmUPTCHP7qb5ERZG4CdMCS6S64/qzZEqijLCqe pwj6j4fV5SyPWEcpxf6ehNdmcfgzVB3Wolfwh1ydhx/96L1jHJcTKchdJJzlfTvq8wwKBgQDeCnKws1t5GapfE1rmC/h4ol L2qZTth9oQmbrXYohVnoqNFslDa43ePZwL9Jmd9kYb0axOTNMmyrP0NTj41uCfgDS0cJnNTc63ojKjegxHIyYDKRZNVUR/d xAYB/vPfBYZUS7M89pO6LLsHhzS3qpu3/hppo/Uc/AM/r8PSflNHQKBgDnWgBh6OQncChPUlOLv9FMZPR1ZOfqLCYrjYEqi uzGm6iKM13zXFO4AGAxu1P/IAd5BovFcTpg79Z8tWqZaUUwvscnl+cRlj+mMXAmdqCeO8VASOmqM1ml667axeZDIR867ZG8 K5V029Wg+4qtX5uFypNAAi6GfHkxIKrD04yOHAoGACdh4wXESi0oiDdkz3KOHPwIjn6BhZC7z8mx+pnJODU3cYukxv3WTct lUhAsyjJiQ/0bK1yX87ulqFVgO0Knmh+wNajrb9wiONAJTMICG7tiWJOm7fW5cfTJwWkBwYADmkfTRmHDvqzQSSvoC2S7aa 9QulbC3C/qgGFNrcWgcT9kCgYAZTa1P9bFCDU7hJc2mHwJwAW7/FQKEJg8SL33KINpLwcR8fqaYOdAHWWz636osVEqosRrH zJOGpf9x2RSWzQJ+dq8+6fACgfFZOVpN644+sAHfNPAI/gnNKU5OfUv+eav8fBnzlf1A3y3GIkyMyzFN3DE7e0n/lyqxE4H BYGpI8g== """ @pytest.fixture() def data() -> Tuple: _id = bytearray({1, 2, 3, 4}) rp_id = "localhost" user_handle = bytearray({1}) privatekey = urlsafe_b64decode(BASE64__ENCODED_PK) sign_count = 0 return (_id, rp_id, user_handle, privatekey, sign_count) def test_rk_enabled_credential(data): _id, rp_id, user_handle, privatekey, sign_count = data credential = Credential.create_resident_credential(_id, rp_id, user_handle, privatekey, sign_count) assert credential.id == urlsafe_b64encode(bytearray({1, 2, 3, 4})).decode() if credential.is_resident_credential is True: assert True assert credential.rp_id == "localhost" assert credential.user_handle == urlsafe_b64encode(bytearray({1})).decode() assert credential.private_key == urlsafe_b64encode(privatekey).decode() assert credential.sign_count == 0 def test_rk_disabled_credentials(data): _id, rp_id, user_handle, privatekey, sign_count = data credential = Credential.create_non_resident_credential(_id, rp_id, privatekey, sign_count) assert credential.id == urlsafe_b64encode(bytearray({1, 2, 3, 4})).decode() assert credential.private_key == urlsafe_b64encode(privatekey).decode() assert credential.sign_count == 0 assert credential.rp_id == "localhost" if credential.is_resident_credential is False: assert True else: assert False if credential.user_handle is None: assert True else: assert False def test_to_dict(data): _id, rp_id, user_handle, privatekey, sign_count = data credential = Credential.create_resident_credential(_id, rp_id, user_handle, privatekey, sign_count) credential_dict = credential.to_dict() assert credential_dict["credentialId"] == urlsafe_b64encode(bytearray({1, 2, 3, 4})).decode() if credential_dict["isResidentCredential"] is True: assert True else: assert False assert credential_dict["rpId"] == "localhost" assert credential_dict["userHandle"] == urlsafe_b64encode(bytearray({1})).decode() assert credential_dict["privateKey"] == urlsafe_b64encode(privatekey).decode() assert credential_dict["signCount"] == 0 def test_from_dict(): data = { "credentialId": urlsafe_b64encode(bytearray({1, 2, 3, 4})).decode(), "isResidentCredential": True, "rpId": "localhost", "userHandle": urlsafe_b64encode(bytearray({1})).decode(), "privateKey": BASE64__ENCODED_PK, "signCount": 0, } credential = Credential.from_dict(data) key = urlsafe_b64decode(BASE64__ENCODED_PK) assert credential.id == urlsafe_b64encode(bytearray({1, 2, 3, 4})).decode() if credential.is_resident_credential is True: assert True else: assert False assert credential.rp_id == "localhost" assert credential.user_handle == urlsafe_b64encode(bytearray({1})).decode() assert credential.private_key == urlsafe_b64encode(key).decode() assert credential.sign_count == 0 selenium-selenium-4.23.0/test/unit/selenium/webdriver/support/0000775000175000017500000000000014646203155024414 5ustar carstencarstenselenium-selenium-4.23.0/test/unit/selenium/webdriver/support/color_tests.py0000664000175000017500000000712714646203155027335 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from selenium.webdriver.support.color import Color def test_color_can_be_subclassed(): class MyColor(Color): pass assert isinstance(MyColor.from_string("rgb(1, 2, 3)"), MyColor) def test_rgb_to_rgb(): rgb = "rgb(1, 2, 3)" assert Color.from_string(rgb).rgb == rgb def test_rgb_to_rgba(): rgb = "rgb(1, 2, 3)" assert Color.from_string(rgb).rgba == "rgba(1, 2, 3, 1)" def test_rgb_pct_to_rgba(): rgb = "rgb(10%, 20%, 30%)" assert Color.from_string(rgb).rgba == "rgba(25, 51, 76, 1)" def test_rgb_allows_whitespace(): rgb = "rgb(\t1, 2 , 3)" assert Color.from_string(rgb).rgb == "rgb(1, 2, 3)" def test_rgba_to_rgba(): rgba = "rgba(1, 2, 3, 0.5)" assert Color.from_string(rgba).rgba == rgba def test_rgba_pct_to_rgba(): rgba = "rgba(10%, 20%, 30%, 0.5)" assert Color.from_string(rgba).rgba == "rgba(25, 51, 76, 0.5)" def test_hex_to_hex(): hex_ = "#ff00a0" assert Color.from_string(hex_).hex == hex_ def test_hex_to_rgb(): hex_ = "#01Ff03" rgb = "rgb(1, 255, 3)" assert Color.from_string(hex_).rgb == rgb def test_hex_to_rgba(): hex_ = "#01Ff03" rgba = "rgba(1, 255, 3, 1)" assert Color.from_string(hex_).rgba == rgba hex_ = "#00ff33" rgba = "rgba(0, 255, 51, 1)" assert Color.from_string(hex_).rgba == rgba def test_rgb_to_hex(): assert Color.from_string("rgb(1, 255, 3)").hex == "#01ff03" def test_hex3_to_rgba(): assert Color.from_string("#0f3").rgba == "rgba(0, 255, 51, 1)" def test_hsl_to_rgba(): hsl = "hsl(120, 100%, 25%)" rgba = "rgba(0, 128, 0, 1)" assert Color.from_string(hsl).rgba == rgba hsl = "hsl(100, 0%, 50%)" rgba = "rgba(128, 128, 128, 1)" assert Color.from_string(hsl).rgba == rgba def test_hsla_to_rgba(): hsla = "hsla(120, 100%, 25%, 1)" rgba = "rgba(0, 128, 0, 1)" assert Color.from_string(hsla).rgba == rgba hsla = "hsla(100, 0%, 50%, 0.5)" rgba = "rgba(128, 128, 128, 0.5)" assert Color.from_string(hsla).rgba == rgba def test_named_color(): assert Color.from_string("green").rgba == "rgba(0, 128, 0, 1)" assert Color.from_string("gray").rgba == "rgba(128, 128, 128, 1)" assert Color.from_string("aqua").hex == "#00ffff" assert Color.from_string("transparent").rgba == "rgba(0, 0, 0, 0)" def test_equals(): assert Color.from_string("#f00") == Color.from_string("rgb(255, 0, 0)") assert Color.from_string("rgba(30, 30, 30, 0.2)") != Color.from_string("rgba(30, 30, 30, 1)") def test_hash(): hash1 = hash(Color.from_string("#f00")) hash2 = hash(Color.from_string("rgb(255, 0, 0)")) assert hash1 == hash2 def test_string_representations(): hex_ = "#01Ff03" assert str(Color.from_string(hex_)) == "Color: rgba(1, 255, 3, 1)" assert repr(Color.from_string(hex_)) == "Color(red=1, green=255, blue=3, alpha=1)" selenium-selenium-4.23.0/test/unit/selenium/webdriver/edge/0000775000175000017500000000000014646203155023604 5ustar carstencarstenselenium-selenium-4.23.0/test/unit/selenium/webdriver/edge/edge_options_tests.py0000664000175000017500000000431314646203155030060 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.options import PageLoadStrategy from selenium.webdriver.edge.options import Options @pytest.fixture def options(): return Options() def test_raises_exception_with_invalid_page_load_strategy(options): with pytest.raises(ValueError): options.page_load_strategy = "never" def test_set_page_load_strategy(options): options.page_load_strategy = PageLoadStrategy.normal caps = options.to_capabilities() assert caps["pageLoadStrategy"] == PageLoadStrategy.normal def test_get_page_load_strategy(options): options._caps["pageLoadStrategy"] = PageLoadStrategy.normal assert options.page_load_strategy == PageLoadStrategy.normal def test_creates_capabilities(options): options.page_load_strategy = PageLoadStrategy.eager caps = options.to_capabilities() assert caps["pageLoadStrategy"] == PageLoadStrategy.eager def test_starts_with_default_capabilities(options): from selenium.webdriver import DesiredCapabilities caps = DesiredCapabilities.EDGE.copy() caps.update({"pageLoadStrategy": PageLoadStrategy.normal}) assert options._caps == caps def test_is_a_baseoptions(options): from selenium.webdriver.common.options import BaseOptions assert isinstance(options, BaseOptions) def test_use_webview(): options = Options() options.use_webview = True caps = options.to_capabilities() assert caps["browserName"] == "webview2" selenium-selenium-4.23.0/test/unit/selenium/webdriver/webkitgtk/0000775000175000017500000000000014646203155024673 5ustar carstencarstenselenium-selenium-4.23.0/test/unit/selenium/webdriver/webkitgtk/webkitgtk_options_tests.py0000664000175000017500000000440714646203155032242 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.options import PageLoadStrategy from selenium.webdriver.webkitgtk.options import Options @pytest.fixture def options(): return Options() def test_set_binary_location(options): options.binary_location = "/foo/bar" assert options._binary_location == "/foo/bar" def test_get_binary_location(options): options._binary_location = "/foo/bar" assert options.binary_location == "/foo/bar" def test_set_overlay_scrollbars_enabled(options): options.overlay_scrollbars_enabled = False assert options._overlay_scrollbars_enabled is False def test_get_overlay_scrollbars_enabled(options): options._overlay_scrollbars_enabled = True assert options.overlay_scrollbars_enabled is True def test_creates_capabilities(options): options._arguments = ["foo"] options._binary_location = "/bar" options._overlay_scrollbars_enabled = True caps = options.to_capabilities() opts = caps.get(Options.KEY) assert opts assert "foo" in opts["args"] assert opts["binary"] == "/bar" assert opts["useOverlayScrollbars"] is True def test_starts_with_default_capabilities(options): from selenium.webdriver import DesiredCapabilities caps = DesiredCapabilities.WEBKITGTK.copy() caps.update({"pageLoadStrategy": PageLoadStrategy.normal}) assert options._caps == caps def test_is_a_baseoptions(options): from selenium.webdriver.common.options import BaseOptions assert isinstance(options, BaseOptions) selenium-selenium-4.23.0/test/unit/selenium/webdriver/wpewebkit/0000775000175000017500000000000014646203155024701 5ustar carstencarstenselenium-selenium-4.23.0/test/unit/selenium/webdriver/wpewebkit/wpewebkit_options_tests.py0000664000175000017500000000356414646203155032261 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.options import PageLoadStrategy from selenium.webdriver.wpewebkit.options import Options @pytest.fixture def options(): return Options() def test_starts_with_default_capabilities(options): from selenium.webdriver import DesiredCapabilities caps = DesiredCapabilities.WPEWEBKIT.copy() caps.update({"pageLoadStrategy": PageLoadStrategy.normal}) assert options._caps == caps def test_set_binary_location(options): options.binary_location = "/foo/bar" assert options._binary_location == "/foo/bar" def test_get_binary_location(options): options._binary_location = "/foo/bar" assert options.binary_location == "/foo/bar" def test_creates_capabilities(options): options._arguments = ["foo"] options._binary_location = "/bar" caps = options.to_capabilities() opts = caps.get(Options.KEY) assert opts assert "foo" in opts["args"] assert opts["binary"] == "/bar" def test_is_a_baseoptions(options): from selenium.webdriver.common.options import BaseOptions assert isinstance(options, BaseOptions) selenium-selenium-4.23.0/test/runner/0000775000175000017500000000000014646203155017420 5ustar carstencarstenselenium-selenium-4.23.0/test/runner/run_pytest.py0000664000175000017500000000205114646203155022204 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest with open("pytest.ini", "w", encoding="utf-8") as ini_file: ini_file.write("[pytest]\n") ini_file.write("addopts = -r=a\n") ini_file.write("rootdir = py\n") ini_file.write("python_files = test_*.py *_tests.py\n") raise SystemExit(pytest.main()) selenium-selenium-4.23.0/AUTHORS0000664000175000017500000010615314646203155016206 0ustar carstencarsten0uk 1kastner <1kastner@users.noreply.github.com> 43081j <43081j@users.noreply.github.com> Aaron Evans Aaron McKinley Abdelrahman Talaat Abdullah Aslam <48642109+code-with-abdullah@users.noreply.github.com> Abhijeet Kasurde Abhilash Thaduka abidema <44252090+abidema@users.noreply.github.com> Adam Dangoor Adam Demuri Adam Goucher Adam Smith AdamPDotty <81536237+AdamPDotty@users.noreply.github.com> Adi Roiban adiohana Aditya Pratap Singh Adrian Dymorz Adrian Leonhard Agustin Pequeno <33221555+aguspe@users.noreply.github.com> Ahmed Ashour AJ Ajay Kemparaj Akhil Lb Akuli Al Sutton Alan Baird Alan Verresen Albert Alberto Alberto Scotto albertor24 Aleksei Moskvin Alex <72409387+fergushev@users.noreply.github.com> Alex Alex Eagle Alex Henrie Alex Rodionov Alex Savchuk Alexander Bayandin Alexander Dobrynin Alexander Kavanaugh Alexander Millin Alexandr Savchuk Alexandre Abreu Alexei Barantsev Alexei Vinogradov Alexey Pelykh Alexis J. Vuillemin Alexis Vuillemin Alfonso Presa Alice Yang aliking Allon Murienik Alpatron Amil Uslu Amit Bhoraniya Amitabh Saikia Anand Bagmar Anand Jayaram Anastasia Vataman Andras Hatvani Andre Wiggins <459878+andrewiggins@users.noreply.github.com> Andreas Tolf Tolfsen Andreas Tolfsen Andrei Andrei Botalov Andrei Rusu Andrei Solntsev Andrey Botalov Andrii Rohovets Andy Duncan anonymous_sdet Anthony Sottile Anton Usmansky Anton Velma Anton Vynogradenko Ardi <47633543+dev-ardi@users.noreply.github.com> Argo Triwidodo Ariel Juodziukynas arnonax arnonax-tr <62980738+arnonax-tr@users.noreply.github.com> Artem Koshelev Artem Kozaev ArthurGIT2017 <25633602+ArthurGIT2017@users.noreply.github.com> Artur Artur Orlov Ashley Trinh Aslak Hellesøy asmundak Atsushi Tatsuma Augustin Gottlieb Pequeno <33221555+aguspe@users.noreply.github.com> Aurélien Pupier Austin Michael Wilkins <42476341+amwilkins@users.noreply.github.com> BaerMitUmlaut Baran Ozgul Bartek Florczak Ben Congleton Ben Kucera <14625260+Bkucera@users.noreply.github.com> Ben Lamm Ben Sedat Benjamin Forehand Jr bgermann bhecquet bhkwan Bill Agee bob Bob Baron Bob Lubecker Bobby Jap Bogdan Bogdan Condurache Bohdan Tkachenko Boni García bootstraponline Boris Osipov Boris Petrov Boris Wrubel bozdemir84 Branden Cash <203336+ammmze@users.noreply.github.com> Brandon Walderman Brandon Williams Brendan Mannix Bret Pettichord Brett Porter Brett Randall Brian Burg Brian Hawley Caleb P. Burns Calin Marina camelmasa Carlos Garcia Campos Carlos Ortega Carlos Villela Carson McDonald ce86f3bb9faf71e <118820152+ce86f3bb9faf71e@users.noreply.github.com> Cervac Petru cezarelnazli ch-saeki <31008335+ch-saeki@users.noreply.github.com> ChanMin Kim Charles Lavery Charles Thomas Chethana Paniyadi Chirag Jayswal chris Chris Block Chris Gamache Chris Martin Chris Mohr Chris Stringer Chris Ward Christian Ansel <36796016+ChrstnAnsl@users.noreply.github.com> Christian Biesinger Christian Clauss Christopher Buttkus Christopher Wood CI Build cjayswal clarkenciel Clay Martin cliffordcheng <48222691+cliffordcheng@users.noreply.github.com> clubfest ColinF colons Connor Shea Corey Goldberg Corey Schooler Coty Rosenblath Craig Nishina CsolG customcommander Cédric Boutillier Dakkaron Damien Allison Damir Dan Fabulich Dana Sherson Daniel Bengtsson Daniel Boelzle [:dbo] Daniel Brown Daniel Davison Daniel Fackrell Daniel Hahler Daniel Montoya Daniel P. Purkhús Daniel Rozenberg Daniel Wagner-Hall Danilo Bargen Danny Staple danvine DanZeuss darek8686 Darrell DeBoer Darren Cotterill Darrin Cherry Dave Hoover Dave Hunt daviande David Burns David English David Fischer David Haeffner David Hewson David Kemp David Lai David Sanders David Shaffer David Vargas David Wang David Zhu Debanjan Choudhury deedy5 <65482418+deedy5@users.noreply.github.com> Denis Demchenko Dennis Oelkers dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Derrick Isaacson DevineLiu <23489096+DevineLiu@users.noreply.github.com> Dharin Shah Dharrya Diego Fernández Santos Diego Molina Dima Kovalenko Dima Veselov Dmitriy Sintsov Dmitry Dubenets Dmitry Tokarev Dmytro Shpakovskyi dnknitro doctor-house <66467615+doctor-house@users.noreply.github.com> Dominik Dary Dominik Rauch Dominik Stadler Donald Pipowitch Dor Blayzer <59066376+Dor-bl@users.noreply.github.com> dosas Doug Simmons Dounia Berrada dratler Dvoryadkin Pavel <52860505+DvoryadkinPavel@users.noreply.github.com> Dylan Lacey Dylan Reichstadt Dylan Semler Earlopain <14981592+Earlopain@users.noreply.github.com> Eberhard Beilharz Ed Manlove Ed Manlove Edi Weissmann Edirin Atumah Eduardo Wermuth Edward Ned Harvey EdwinVanVliet Ela Makiej elgatov Eli Flanagan Elias Faxö Ellis Percival Enrique Daimiel eoff Eran Messeri Eric Allen Eric Plaster Erik Beans Erik E. Beerepoot Erik Kuefler Evan Sangaline Evgeniy Roldukhin EwaMarek Fan <1135611487@qq.com> Felipe Knorr Kuhn Fenil Mehta <42742240+fenilgmehta@users.noreply.github.com> Florian Apolloner Florian LOPES Florian Mutter <32459530+florianmutter@users.noreply.github.com> Florian Zipperle Francis Bergin Franz Liedke François Freitag François JACQUES François Reynaud Frederik Carlier Fredrik Wollsén freynaud FrySabotage Fumiaki MATSUSHIMA fuyou Gaurav gentoo90 George Adams Georgii Dolzhykov Gerald Ehmayer Gerry Gao Gestalt LUR GFHuang <4510984+GF-Huang@users.noreply.github.com> ggkiokas <115367874+ggkiokas@users.noreply.github.com> Ghjuvan Lacambre Giorgos Tzampanakis glaszig Glib Briia Godefroid Chapelle Godefroid Chapelle gopackgo90 Gopal Patel GPT14 GQAssurance <34662917+GQAssurance@users.noreply.github.com> Grace Tang Graham Russell granak Grant <34662917+GQAssurance@users.noreply.github.com> Greg Fraley Greg Hogan Gregory Block gregory.kleiner@accolade.com Grey Li Grigory Mischenko Grzegorz Halat Guangyue Xu <64437609+guangyuexu@users.noreply.github.com> Guilherme Sousa <33522742+dilhelh@users.noreply.github.com> Guille h-arlt Hamir Mahal Hanbo Wang haqer1 Harmandeep Singh Harry Harshit Agrawal <94462364+harshit-bs@users.noreply.github.com> havja Haw-bin Chai hectorhon Heky helen3141 <54561656+helen3141@users.noreply.github.com> Henrik Skupin Herryanto Siatono Herst Hiroaki Ninomiya Hirotaka Tagawa / wafuwafu13 hornyja4 Hugo van Kemenade huntr-helper Hyesung Lee Iain Dawson Iain Dawson Ian Lesperance ian zhang Iaroslav Naidon ifland Ilya Kozhevnikov Ilyas Bayraktar Immanuel Hayden Indomitable Innokenty Shuvalov Isaac A. Murchie Isaul Vargas Ish Abbi Ivan De Marino Ivan Kalinin Ivan Krutov Ivan Pozdeev J.D. Purcell Jack Allen <38332643+jackall3n@users.noreply.github.com> Jacob Kiesel Jacob Walls Jacob Wejendorp Jake Jake Garelick Jake Klingensmith Jakub Vrána jamadam James Braza James Cooper James Garbutt <43081j@users.noreply.github.com> James Hilliard James Martin James Strachen James Yuzawa jamespdo Jan Trejbal Jan Weitz Jane Tymoschuk Jani Hautakangas Jared Webber Jari Bakken Jason Jason Anderson Jason Carr Jason Hu Jason Huggins Jason Juang Jason Leyba Jason Parry Jason Watt Javier Candeira Jayakumar Chinnappan Jayasankar Jayme Jayson Smith Jean-Francois Roche Jeff Moore Jeff Xiong Jennifer Bevan Jens Diemer Jeremy Herault Jeroen van Warmerdam jerome-nexedi Jerry Pussinen JerryJia jess010 Jesserd July Jewen Xiao Jiahua Fan Jiayao Yu Jie Tina Wang Jigar wala Jim Jim Brännlund Jim Brännlund Jim Evans Jim Reid Jim van Musscher jkbzh <3439365+jkbzh@users.noreply.github.com> jkohls jmuramatsu Joaquín Romero jochenberger Joe Bandenburg Joe Lencioni Joe Schulte Joe Walnes Joel Hillacre joe_schulte Johan Lorenzo JohanBrorson John Barbuto John Chen John Comeau John Dorlus John F. Douthat John J. Barton John Pelly Johnny.H Johnson <20457146+j3soon@users.noreply.github.com> joma74 Jon Dufresne Jon Spalding Jon Wallsten Jonah Jonah Stiennon Jonatan Kronqvist Jonathan Leitschuh Jonathan Lipps Jonathon Kereliuk Jongkuen Hong Jordan Mace josephg Josh Goldberg Joshua Bruning Joshua Fehler Joshua Grant João Luca Ripardo JT Archie jugglinmike Julian Didier Julian Harty Julian Kung Julie Ralph Julien Phalip Junpei Kawamoto juperala JustasM <59362982+JustasMonkev@users.noreply.github.com> Justin Tulloss Justine Tunney justinwoolley@gmail.com jwoolley <19597672+jwoolley@users.noreply.github.com> Jörg Sautter Kamen Litchev Karl Kuehn Karl-Philipp Richter kateposener katrina95 <34797724+katrina95@users.noreply.github.com> Kazuaki Matsuo Kazuhiro NISHIYAMA Kazuki Higashiguchi keenangraham Ken Kania Kensuke Numakura KentGu Kevin C Kevin Dew Kevin Menard kevin.cho Kian Eliasi Kian Meng Ang Kim Hyeonseok kjleftin Konstantin Kotenko <36271666+kkotenko@users.noreply.github.com> kou1okada Kouzukii Kris <1611248+Rinzwind@users.noreply.github.com> Krishna Suravarapu <36037520+KrishnaSuravarapu@users.noreply.github.com> Krishnan Mahadevan Kristian Rosenvold Krzysztof Księżyk kuhtich Kunal Gosar kurniady@gmail.com Kurt Alfred Kluever kvetko <37440134+kvetko@users.noreply.github.com> Kyle McGonagle Lamberto Larry Diamond <1066589+larrydiamond@users.noreply.github.com> Larry Yu larsiver Laura Laurence Rowe Lauro Moura Leo Laskin Leon Shams <52867365+LeonShams@users.noreply.github.com> Leonardo Salles Levi Noecker lhuang Long Ly Long Nguyen lsowen Lucas Diniz Lucas Tierney Luis Correia Luis Pflamminger Luke Hill Luke Inman-Semerau lukec Lukáš Linhart Lyudmil Latinov Machinexa2 <60662297+machinexa2@users.noreply.github.com> Maciej Pakulski Magnus E. Halvorsen Maid <37146904+ParadiseWitch@users.noreply.github.com> Malcolm Rowe MandarJKulkarni <33712629+MandarJKulkarni@users.noreply.github.com> Maneesh MS Manoj Kumar Manuel Blanco Marc Fisher Marc Guillemot Marc Schlegel Marcel Wilson Marcin Strzyz <37447884+mastrzyz@users.noreply.github.com> marcotcr Marcus Merrell Maria Filonova Mark Banner Mark Charsley Mark Christian Mark Collin Mark Mayo Mark Stacey Mark Watson Marvin A. Ruder Marvin Ojwang MASACR99 Masayuki Hokimoto Mateusz Kajka <18029907+codemrkay@users.noreply.github.com> Mathias Kresin Mathias Rangel Wulff mathlang Matt McCartney Matt Q Matthew Kempkers <118692289+matt-kemp-m2x@users.noreply.github.com> Matthew Lymer Matthew Rahtz matthewdoerksen MatzFan Max Perrello Max Schmitt Maxim Lobanov Maxim Perepelitsa mcharsley Meir Blachman Melroy van den Berg Michael Benz Michael Glass Michael Keeley Michael Klepikov Michael Mintz Michael Nikitochkin Michael P. Jung Michael Render Michael Tamm Michael Zhou Michal Čihař Michał Herda Michele Sama Mickaël Schoentgen Microsoft Provenance Contributions middlingphys <38708390+middlingphys@users.noreply.github.com> Miguel Carboni Mike Bellew Mike Melia Mike Pennisi Mike Roberts Mike Williams Mikhail Fedosov Mikhail Panin Miki Tebeka Mikko Tiihonen Milan Falešník ming Mirko Nasato mitchloudenbeck Miten Chauhan mkvetko MMK-IBSEN <124664589+MMK-IBSEN@users.noreply.github.com> Mohab Mohie mohammadsavadkuhi Moisés Moritz Kiefer Moritz Sichert morrishoresh morskyrv <18137385+morskyrv@users.noreply.github.com> Moshe Atlow mpurland mtrea <32470080+mtrea@users.noreply.github.com> Mubariz Hajimuradov Muhammad Hammad <33136628+mhnaeem@users.noreply.github.com> Muthu Kannan MWschutte <72599545+MWschutte@users.noreply.github.com> myslak71 Nate Lowry Nathan Isom native-api Naveen <172697+naveensrinivasan@users.noreply.github.com> Naveen Singh <36371707+Naveen3Singh@users.noreply.github.com> Neil Carvalho Nelson Sproul Nick Crews Nick Gaya Nick Schonning Nicolas Sotgui Nik Nyby Nikhil Agarwal Nikolay Borisenko Nina Satragno nir-tal-talkspace <71274151+nir-tal-talkspace@users.noreply.github.com> Nirantak Raghav Nitish Noel Gordon Nowell Strite Nozomi Ito no_author nvonop Oboleninov Anton Oleg Höfling Oleg Ridchenko <73664101+oleg-rd@users.noreply.github.com> Oleksandr Kulychok Oleksandr Kulychok Oleksii Olivier SCHNEIDER Olle Jonsson Olly Dean Ondřej Machulda Ondřej Čertík orangeudav Oscar Devora <100381276+RevealOscar@users.noreply.github.com> Outsider Paladin Wang <49390614+eversoutheast@users.noreply.github.com> Palmer Bandy <37938675+palmermbandy@users.noreply.github.com> Pat Tullmann Patrice Jaton Patrick Beart Patrick Gansterer Patrick Lightbody Paul G Webster Paul Hammant Pavel Lobashov Perryn Fowler Pete Johns Peter Hedenskog Peter M. Landwehr petruc Phani Rithvij Philipp Hancke Philippe Hanrigou Phillip Haydon phoenix384 pinterior Piotr Witoslawski pitachips PombaM Potapov Dmitriy Prakhar Rawat praveendvd <45095911+praveendvd@users.noreply.github.com> Puja Jagani Pulkit Sharma Pydi Chandra Qays H. Poonawala Radosław Sporny Rafael Chavez Rahul Shah Rajendra Kadam Ram Rachum Rami Ravi Sawlani rbri rchatley rchatley@gmail.com reichsta Reinaldo Rossetti Reinhold Degenfellner Remco renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> richard.hines RichCrook richseviora Rishav Trivedi Rob Richardson Rob Wu Robert Elliot Robert Fletcher Roberto Rivera Robin Stocker Rod McNew Roman Yurchak Roman Yurchak Roman Zoller rompic Rory Craig-Barnes Roubal Sehgal <44202409+roubalsehgal@users.noreply.github.com> Rouke Broersma roushikk rovner Rune Flobakk Russ Amos RussiaVk <43515485+RussiaVk@users.noreply.github.com> RustyNail Ryan Fitzpatrick Ryan Wilcox Ryszard Perkowski Sajad Torkamani Saksham Gupta Salvador Cabrera Lozano Sam Uong Samit Badle Samuel Bétrisey Sandeep Suryaprasad <26169602+sandeepsuryaprasad@users.noreply.github.com> Sankha Narayan Guria Santiago Suarez Ordoñez Sarah Bird Sayyid Ali Sajjad Rizavi <58586026+ali-sajjad-rizavi@users.noreply.github.com> schrufygroovy <50398024+schrufygroovy@users.noreply.github.com> Scott Babcock Scott Sauber Scott Stevens Sean Gomez <34379448+Sean-Gomez@users.noreply.github.com> Sean Poulter seanrand57 Sebastian Meyer Sebastian Monte Sebastien Guillemot seidnerj Selenium CI Bot Selenium CI Bot Sen ZmaKi <90490506+SenZmaKi@users.noreply.github.com> Sergey Chipiga Sergey Fursov Sergey Tikhomirov Seth Lemanek Seva Lotoshnikov Shan Shashank <42868640+snsten@users.noreply.github.com> Shay Dratler Shengfa <3363396+k7z45@users.noreply.github.com> shin Shinya Kasatani Shishu Raj Pandey Shreyan Avigyan <74560907+shreyanavigyan@users.noreply.github.com> Shubham Singh <41840111+singh811@users.noreply.github.com> Shuhai Shen Simon K Simon Perepelitsa Simon Stewart skratchdot smhc Snail space88man Sri Harsha Sri Harsha sridharUpputuri <52928428+sridharUpputuri@users.noreply.github.com> Srinivasan Sekar Sripathi Pai Sruthi Stanley Hon Stanley Hon Stephen Kuenzli Steve Brown Steve Smith Steven Hazel stevetracvc <70416691+stevetracvc@users.noreply.github.com> Stoyan Dimkov Stuart Knightly sufyanAbbasi sugama sunnyyukaige symonk Take take0x <89313929+take0x@users.noreply.github.com> Takeshi Kishi Takuho NAKANO Takuma Chiba Tamas Utasi <3823780+utamas@users.noreply.github.com> Tamsil Sajid Amani Tamás Buka Tatsuya Hoshino Terence Haddock thecr8tr Thomas Flori Thomas Grainger Thomas Walpole Thunderforge Tim Sutton Tim van der Lippe timm-permeance Timofey Vasenin Timur Zolotuhin ting <44369205+71n9@users.noreply.github.com> tirana Titus Fortner Tobias Lidskog Tobias Smolka <37370256+tosmolka@users.noreply.github.com> Toda Hiroshi Toilal Tom Longhurst Tom Trumper tomaszn Tomer Steinfeld Tommy Beadle tommywo Tomohiro Endo Tony Hignett Tony Narlock tporeba trabulmonkee trademark18 Trey Chadick Tricia Crichton TriciaCrichton <54917582+TriciaCrichton@users.noreply.github.com> Trig Troy Walsh ttanaka tvataire Ulf Adams Ulrich Buchgraber User253489 V24 <55334829+umarfarouk98@users.noreply.github.com> Valery Yatsynovich Varun Menon varunsurapaneni <67070327+varunsurapaneni@users.noreply.github.com> Vedanth Vasu Dev <61700595+vedanthvdev@users.noreply.github.com> vedanthvdev <61700595+vedanthvdev@users.noreply.github.com> vergiliu vflame <0x484x0@gmail.com> Victor Tang Viet Nguyen Duc Vijay Singh Vijendarn Selvarajah <11275608+vijay44@users.noreply.github.com> VijendraEAtech <39116868+VijendraEAtech@users.noreply.github.com> Vikas Goel VimalRaj Selvam Vincent Ladeuil vinoth959 Viren Negi <63040+meetme2meat@users.noreply.github.com> Virender Singh Vishnuprakash P K Vitaliy Potapov Vladimir Támara Patiño VladimirPodolyan <36446855+VladimirPodolyan@users.noreply.github.com> Vladislav Velichko <111522705+vlad8x8@users.noreply.github.com> Vyvyan Codd Václav Votípka Werner Robitza wiggin15 wildloop WORKSTATION02 wpc y-yagi Yaroslav Admin Yash Ladha <201551061@iiitvadodara.ac.in> Yehuda Davis Yevgeniy Shunevych Yi Zeng yk9772 <93392713+yk9772@users.noreply.github.com> Yurii Karabas <1998uriyyo@gmail.com> Yusuke Noda <91508381+yusuke-noda@users.noreply.github.com> Zach Attas Zeki Mokhtarzada zhangwenqiang00 Zhuo Peng Ziyu Zoltar - Knower of All zsong Ákos Lukács Étienne Barrié 保木本将之 selenium-selenium-4.23.0/README.rst0000777000175000017500000000000014646203155022703 2docs/source/index.rstustar carstencarsten