cumulusci-plus 5.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of cumulusci-plus might be problematic. Click here for more details.

Files changed (744) hide show
  1. cumulusci/__about__.py +1 -0
  2. cumulusci/__init__.py +22 -0
  3. cumulusci/__main__.py +3 -0
  4. cumulusci/cli/__init__.py +0 -0
  5. cumulusci/cli/cci.py +244 -0
  6. cumulusci/cli/error.py +125 -0
  7. cumulusci/cli/flow.py +185 -0
  8. cumulusci/cli/logger.py +72 -0
  9. cumulusci/cli/org.py +692 -0
  10. cumulusci/cli/plan.py +181 -0
  11. cumulusci/cli/project.py +391 -0
  12. cumulusci/cli/robot.py +116 -0
  13. cumulusci/cli/runtime.py +190 -0
  14. cumulusci/cli/service.py +521 -0
  15. cumulusci/cli/task.py +295 -0
  16. cumulusci/cli/tests/__init__.py +0 -0
  17. cumulusci/cli/tests/test_cci.py +545 -0
  18. cumulusci/cli/tests/test_error.py +170 -0
  19. cumulusci/cli/tests/test_flow.py +276 -0
  20. cumulusci/cli/tests/test_logger.py +25 -0
  21. cumulusci/cli/tests/test_org.py +1438 -0
  22. cumulusci/cli/tests/test_plan.py +245 -0
  23. cumulusci/cli/tests/test_project.py +235 -0
  24. cumulusci/cli/tests/test_robot.py +177 -0
  25. cumulusci/cli/tests/test_runtime.py +197 -0
  26. cumulusci/cli/tests/test_service.py +853 -0
  27. cumulusci/cli/tests/test_task.py +266 -0
  28. cumulusci/cli/tests/test_ui.py +310 -0
  29. cumulusci/cli/tests/test_utils.py +122 -0
  30. cumulusci/cli/tests/utils.py +52 -0
  31. cumulusci/cli/ui.py +234 -0
  32. cumulusci/cli/utils.py +150 -0
  33. cumulusci/conftest.py +181 -0
  34. cumulusci/core/__init__.py +0 -0
  35. cumulusci/core/config/BaseConfig.py +5 -0
  36. cumulusci/core/config/BaseTaskFlowConfig.py +5 -0
  37. cumulusci/core/config/OrgConfig.py +5 -0
  38. cumulusci/core/config/ScratchOrgConfig.py +5 -0
  39. cumulusci/core/config/__init__.py +125 -0
  40. cumulusci/core/config/base_config.py +111 -0
  41. cumulusci/core/config/base_task_flow_config.py +82 -0
  42. cumulusci/core/config/marketing_cloud_service_config.py +83 -0
  43. cumulusci/core/config/oauth2_service_config.py +17 -0
  44. cumulusci/core/config/org_config.py +604 -0
  45. cumulusci/core/config/project_config.py +782 -0
  46. cumulusci/core/config/scratch_org_config.py +251 -0
  47. cumulusci/core/config/sfdx_org_config.py +220 -0
  48. cumulusci/core/config/tests/_test_config_backwards_compatibility.py +33 -0
  49. cumulusci/core/config/tests/test_config.py +1895 -0
  50. cumulusci/core/config/tests/test_config_expensive.py +839 -0
  51. cumulusci/core/config/tests/test_config_util.py +91 -0
  52. cumulusci/core/config/universal_config.py +88 -0
  53. cumulusci/core/config/util.py +18 -0
  54. cumulusci/core/datasets.py +303 -0
  55. cumulusci/core/debug.py +33 -0
  56. cumulusci/core/dependencies/__init__.py +55 -0
  57. cumulusci/core/dependencies/base.py +561 -0
  58. cumulusci/core/dependencies/dependencies.py +273 -0
  59. cumulusci/core/dependencies/github.py +177 -0
  60. cumulusci/core/dependencies/github_resolvers.py +244 -0
  61. cumulusci/core/dependencies/resolvers.py +580 -0
  62. cumulusci/core/dependencies/tests/__init__.py +0 -0
  63. cumulusci/core/dependencies/tests/conftest.py +385 -0
  64. cumulusci/core/dependencies/tests/test_dependencies.py +950 -0
  65. cumulusci/core/dependencies/tests/test_github.py +83 -0
  66. cumulusci/core/dependencies/tests/test_resolvers.py +1027 -0
  67. cumulusci/core/dependencies/utils.py +13 -0
  68. cumulusci/core/enums.py +11 -0
  69. cumulusci/core/exceptions.py +311 -0
  70. cumulusci/core/flowrunner.py +888 -0
  71. cumulusci/core/github.py +665 -0
  72. cumulusci/core/keychain/__init__.py +24 -0
  73. cumulusci/core/keychain/base_project_keychain.py +441 -0
  74. cumulusci/core/keychain/encrypted_file_project_keychain.py +945 -0
  75. cumulusci/core/keychain/environment_project_keychain.py +7 -0
  76. cumulusci/core/keychain/serialization.py +152 -0
  77. cumulusci/core/keychain/subprocess_keychain.py +24 -0
  78. cumulusci/core/keychain/tests/conftest.py +50 -0
  79. cumulusci/core/keychain/tests/test_base_project_keychain.py +299 -0
  80. cumulusci/core/keychain/tests/test_encrypted_file_project_keychain.py +1228 -0
  81. cumulusci/core/metadeploy/__init__.py +0 -0
  82. cumulusci/core/metadeploy/api.py +88 -0
  83. cumulusci/core/metadeploy/plans.py +25 -0
  84. cumulusci/core/metadeploy/tests/test_api.py +276 -0
  85. cumulusci/core/runtime.py +115 -0
  86. cumulusci/core/sfdx.py +162 -0
  87. cumulusci/core/source/__init__.py +16 -0
  88. cumulusci/core/source/github.py +50 -0
  89. cumulusci/core/source/local_folder.py +35 -0
  90. cumulusci/core/source_transforms/__init__.py +0 -0
  91. cumulusci/core/source_transforms/tests/test_transforms.py +1091 -0
  92. cumulusci/core/source_transforms/transforms.py +532 -0
  93. cumulusci/core/tasks.py +404 -0
  94. cumulusci/core/template_utils.py +59 -0
  95. cumulusci/core/tests/__init__.py +0 -0
  96. cumulusci/core/tests/cassettes/TestDatasetsE2E.test_datasets_e2e.yaml +215 -0
  97. cumulusci/core/tests/cassettes/TestDatasetsE2E.test_datasets_extract_standard_objects.yaml +199 -0
  98. cumulusci/core/tests/cassettes/TestDatasetsE2E.test_datasets_read_explicit_extract_declaration.yaml +3 -0
  99. cumulusci/core/tests/fake_remote_repo/cumulusci.yml +32 -0
  100. cumulusci/core/tests/fake_remote_repo/tasks/directory/example_2.py +6 -0
  101. cumulusci/core/tests/fake_remote_repo/tasks/example.py +43 -0
  102. cumulusci/core/tests/fake_remote_repo_2/cumulusci.yml +11 -0
  103. cumulusci/core/tests/fake_remote_repo_2/tasks/example_3.py +6 -0
  104. cumulusci/core/tests/test_datasets_e2e.py +386 -0
  105. cumulusci/core/tests/test_exceptions.py +11 -0
  106. cumulusci/core/tests/test_flowrunner.py +836 -0
  107. cumulusci/core/tests/test_github.py +942 -0
  108. cumulusci/core/tests/test_sfdx.py +138 -0
  109. cumulusci/core/tests/test_source.py +678 -0
  110. cumulusci/core/tests/test_tasks.py +262 -0
  111. cumulusci/core/tests/test_utils.py +141 -0
  112. cumulusci/core/tests/test_utils_merge_config.py +276 -0
  113. cumulusci/core/tests/test_versions.py +76 -0
  114. cumulusci/core/tests/untrusted_repo_child/cumulusci.yml +7 -0
  115. cumulusci/core/tests/untrusted_repo_child/tasks/untrusted_child.py +6 -0
  116. cumulusci/core/tests/untrusted_repo_parent/cumulusci.yml +26 -0
  117. cumulusci/core/tests/untrusted_repo_parent/tasks/untrusted_parent.py +6 -0
  118. cumulusci/core/tests/utils.py +116 -0
  119. cumulusci/core/tests/yaml/global.yaml +0 -0
  120. cumulusci/core/utils.py +402 -0
  121. cumulusci/core/versions.py +149 -0
  122. cumulusci/cumulusci.yml +1621 -0
  123. cumulusci/files/admin_profile.xml +20 -0
  124. cumulusci/files/delete_excludes.txt +424 -0
  125. cumulusci/files/templates/project/README.md +12 -0
  126. cumulusci/files/templates/project/cumulusci.yml +63 -0
  127. cumulusci/files/templates/project/dot-gitignore +60 -0
  128. cumulusci/files/templates/project/mapping.yml +45 -0
  129. cumulusci/files/templates/project/scratch_def.json +25 -0
  130. cumulusci/oauth/__init__.py +0 -0
  131. cumulusci/oauth/client.py +400 -0
  132. cumulusci/oauth/exceptions.py +9 -0
  133. cumulusci/oauth/salesforce.py +95 -0
  134. cumulusci/oauth/tests/__init__.py +0 -0
  135. cumulusci/oauth/tests/cassettes/test_get_device_code.yaml +22 -0
  136. cumulusci/oauth/tests/cassettes/test_get_device_oauth_token.yaml +74 -0
  137. cumulusci/oauth/tests/test_client.py +308 -0
  138. cumulusci/oauth/tests/test_salesforce.py +46 -0
  139. cumulusci/plugins/__init__.py +3 -0
  140. cumulusci/plugins/plugin_base.py +93 -0
  141. cumulusci/plugins/plugin_loader.py +59 -0
  142. cumulusci/robotframework/CumulusCI.py +340 -0
  143. cumulusci/robotframework/CumulusCI.robot +7 -0
  144. cumulusci/robotframework/Performance.py +165 -0
  145. cumulusci/robotframework/Salesforce.py +936 -0
  146. cumulusci/robotframework/Salesforce.robot +192 -0
  147. cumulusci/robotframework/SalesforceAPI.py +416 -0
  148. cumulusci/robotframework/SalesforcePlaywright.py +220 -0
  149. cumulusci/robotframework/SalesforcePlaywright.robot +40 -0
  150. cumulusci/robotframework/__init__.py +2 -0
  151. cumulusci/robotframework/base_library.py +39 -0
  152. cumulusci/robotframework/faker_mixin.py +89 -0
  153. cumulusci/robotframework/form_handlers.py +222 -0
  154. cumulusci/robotframework/javascript/cci_init.js +34 -0
  155. cumulusci/robotframework/javascript/cumulusci.js +4 -0
  156. cumulusci/robotframework/locator_manager.py +197 -0
  157. cumulusci/robotframework/locators_56.py +88 -0
  158. cumulusci/robotframework/locators_57.py +5 -0
  159. cumulusci/robotframework/pageobjects/BasePageObjects.py +433 -0
  160. cumulusci/robotframework/pageobjects/ObjectManagerPageObject.py +246 -0
  161. cumulusci/robotframework/pageobjects/PageObjectLibrary.py +45 -0
  162. cumulusci/robotframework/pageobjects/PageObjects.py +351 -0
  163. cumulusci/robotframework/pageobjects/__init__.py +12 -0
  164. cumulusci/robotframework/pageobjects/baseobjects.py +120 -0
  165. cumulusci/robotframework/perftests/short/collection_perf.robot +105 -0
  166. cumulusci/robotframework/tests/CustomObjectTestPage.py +10 -0
  167. cumulusci/robotframework/tests/FooTestPage.py +8 -0
  168. cumulusci/robotframework/tests/cumulusci/base.robot +40 -0
  169. cumulusci/robotframework/tests/cumulusci/bulkdata.robot +38 -0
  170. cumulusci/robotframework/tests/cumulusci/communities.robot +57 -0
  171. cumulusci/robotframework/tests/cumulusci/datagen.robot +84 -0
  172. cumulusci/robotframework/tests/salesforce/TestLibraryA.py +24 -0
  173. cumulusci/robotframework/tests/salesforce/TestLibraryB.py +20 -0
  174. cumulusci/robotframework/tests/salesforce/TestListener.py +93 -0
  175. cumulusci/robotframework/tests/salesforce/api.robot +178 -0
  176. cumulusci/robotframework/tests/salesforce/browsers.robot +143 -0
  177. cumulusci/robotframework/tests/salesforce/classic.robot +51 -0
  178. cumulusci/robotframework/tests/salesforce/create_contact.robot +59 -0
  179. cumulusci/robotframework/tests/salesforce/faker.robot +68 -0
  180. cumulusci/robotframework/tests/salesforce/forms.robot +172 -0
  181. cumulusci/robotframework/tests/salesforce/label_locator.robot +244 -0
  182. cumulusci/robotframework/tests/salesforce/labels.html +33 -0
  183. cumulusci/robotframework/tests/salesforce/locators.robot +149 -0
  184. cumulusci/robotframework/tests/salesforce/pageobjects/base_pageobjects.robot +100 -0
  185. cumulusci/robotframework/tests/salesforce/pageobjects/example_page_object.py +25 -0
  186. cumulusci/robotframework/tests/salesforce/pageobjects/listing_page.robot +115 -0
  187. cumulusci/robotframework/tests/salesforce/pageobjects/objectmanager.robot +74 -0
  188. cumulusci/robotframework/tests/salesforce/pageobjects/pageobjects.robot +171 -0
  189. cumulusci/robotframework/tests/salesforce/performance.robot +109 -0
  190. cumulusci/robotframework/tests/salesforce/playwright/javascript_keywords.robot +33 -0
  191. cumulusci/robotframework/tests/salesforce/playwright/open_test_browser.robot +48 -0
  192. cumulusci/robotframework/tests/salesforce/playwright/playwright.robot +24 -0
  193. cumulusci/robotframework/tests/salesforce/playwright/ui.robot +32 -0
  194. cumulusci/robotframework/tests/salesforce/populate.robot +89 -0
  195. cumulusci/robotframework/tests/salesforce/test_testlistener.py +37 -0
  196. cumulusci/robotframework/tests/salesforce/ui.robot +361 -0
  197. cumulusci/robotframework/tests/test_cumulusci_library.py +304 -0
  198. cumulusci/robotframework/tests/test_locator_manager.py +158 -0
  199. cumulusci/robotframework/tests/test_pageobjects.py +291 -0
  200. cumulusci/robotframework/tests/test_performance.py +38 -0
  201. cumulusci/robotframework/tests/test_salesforce.py +79 -0
  202. cumulusci/robotframework/tests/test_salesforce_locators.py +73 -0
  203. cumulusci/robotframework/tests/test_template_util.py +53 -0
  204. cumulusci/robotframework/tests/test_utils.py +106 -0
  205. cumulusci/robotframework/utils.py +283 -0
  206. cumulusci/salesforce_api/__init__.py +0 -0
  207. cumulusci/salesforce_api/exceptions.py +23 -0
  208. cumulusci/salesforce_api/filterable_objects.py +96 -0
  209. cumulusci/salesforce_api/mc_soap_envelopes.py +89 -0
  210. cumulusci/salesforce_api/metadata.py +721 -0
  211. cumulusci/salesforce_api/org_schema.py +571 -0
  212. cumulusci/salesforce_api/org_schema_models.py +226 -0
  213. cumulusci/salesforce_api/package_install.py +265 -0
  214. cumulusci/salesforce_api/package_zip.py +301 -0
  215. cumulusci/salesforce_api/rest_deploy.py +148 -0
  216. cumulusci/salesforce_api/retrieve_profile_api.py +301 -0
  217. cumulusci/salesforce_api/soap_envelopes.py +177 -0
  218. cumulusci/salesforce_api/tests/__init__.py +0 -0
  219. cumulusci/salesforce_api/tests/metadata_test_strings.py +24 -0
  220. cumulusci/salesforce_api/tests/test_metadata.py +1015 -0
  221. cumulusci/salesforce_api/tests/test_package_install.py +219 -0
  222. cumulusci/salesforce_api/tests/test_package_zip.py +380 -0
  223. cumulusci/salesforce_api/tests/test_rest_deploy.py +264 -0
  224. cumulusci/salesforce_api/tests/test_retrieve_profile_api.py +337 -0
  225. cumulusci/salesforce_api/tests/test_utils.py +124 -0
  226. cumulusci/salesforce_api/utils.py +51 -0
  227. cumulusci/schema/cumulusci.jsonschema.json +782 -0
  228. cumulusci/tasks/__init__.py +0 -0
  229. cumulusci/tasks/apex/__init__.py +0 -0
  230. cumulusci/tasks/apex/anon.py +157 -0
  231. cumulusci/tasks/apex/batch.py +180 -0
  232. cumulusci/tasks/apex/testrunner.py +835 -0
  233. cumulusci/tasks/apex/tests/cassettes/ManualEditTestApexIntegrationTests.test_run_tests__integration_test.yaml +703 -0
  234. cumulusci/tasks/apex/tests/test_apex_tasks.py +1558 -0
  235. cumulusci/tasks/base_source_control_task.py +17 -0
  236. cumulusci/tasks/bulkdata/__init__.py +15 -0
  237. cumulusci/tasks/bulkdata/base_generate_data_task.py +96 -0
  238. cumulusci/tasks/bulkdata/dates.py +97 -0
  239. cumulusci/tasks/bulkdata/delete.py +156 -0
  240. cumulusci/tasks/bulkdata/extract.py +441 -0
  241. cumulusci/tasks/bulkdata/extract_dataset_utils/calculate_dependencies.py +117 -0
  242. cumulusci/tasks/bulkdata/extract_dataset_utils/extract_yml.py +123 -0
  243. cumulusci/tasks/bulkdata/extract_dataset_utils/hardcoded_default_declarations.py +49 -0
  244. cumulusci/tasks/bulkdata/extract_dataset_utils/synthesize_extract_declarations.py +283 -0
  245. cumulusci/tasks/bulkdata/extract_dataset_utils/tests/test_extract_yml.py +142 -0
  246. cumulusci/tasks/bulkdata/extract_dataset_utils/tests/test_synthesize_extract_declarations.py +575 -0
  247. cumulusci/tasks/bulkdata/factory_utils.py +134 -0
  248. cumulusci/tasks/bulkdata/generate.py +4 -0
  249. cumulusci/tasks/bulkdata/generate_and_load_data.py +232 -0
  250. cumulusci/tasks/bulkdata/generate_and_load_data_from_yaml.py +19 -0
  251. cumulusci/tasks/bulkdata/generate_from_yaml.py +183 -0
  252. cumulusci/tasks/bulkdata/generate_mapping.py +434 -0
  253. cumulusci/tasks/bulkdata/generate_mapping_utils/dependency_map.py +169 -0
  254. cumulusci/tasks/bulkdata/generate_mapping_utils/extract_mapping_file_generator.py +45 -0
  255. cumulusci/tasks/bulkdata/generate_mapping_utils/generate_mapping_from_declarations.py +121 -0
  256. cumulusci/tasks/bulkdata/generate_mapping_utils/load_mapping_file_generator.py +127 -0
  257. cumulusci/tasks/bulkdata/generate_mapping_utils/mapping_generator_post_processes.py +53 -0
  258. cumulusci/tasks/bulkdata/generate_mapping_utils/mapping_transforms.py +139 -0
  259. cumulusci/tasks/bulkdata/generate_mapping_utils/tests/test_generate_extract_mapping_from_declarations.py +135 -0
  260. cumulusci/tasks/bulkdata/generate_mapping_utils/tests/test_generate_load_mapping_from_declarations.py +330 -0
  261. cumulusci/tasks/bulkdata/generate_mapping_utils/tests/test_mapping_generator_post_processes.py +60 -0
  262. cumulusci/tasks/bulkdata/generate_mapping_utils/tests/test_mapping_transforms.py +188 -0
  263. cumulusci/tasks/bulkdata/load.py +1196 -0
  264. cumulusci/tasks/bulkdata/mapping_parser.py +811 -0
  265. cumulusci/tasks/bulkdata/query_transformers.py +264 -0
  266. cumulusci/tasks/bulkdata/select_utils.py +792 -0
  267. cumulusci/tasks/bulkdata/snowfakery.py +753 -0
  268. cumulusci/tasks/bulkdata/snowfakery_utils/queue_manager.py +478 -0
  269. cumulusci/tasks/bulkdata/snowfakery_utils/snowfakery_run_until.py +141 -0
  270. cumulusci/tasks/bulkdata/snowfakery_utils/snowfakery_working_directory.py +53 -0
  271. cumulusci/tasks/bulkdata/snowfakery_utils/subtask_configurator.py +64 -0
  272. cumulusci/tasks/bulkdata/step.py +1242 -0
  273. cumulusci/tasks/bulkdata/tests/__init__.py +0 -0
  274. cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_random_strategy.yaml +147 -0
  275. cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_similarity_annoy_strategy.yaml +123 -0
  276. cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_similarity_select_and_insert_strategy.yaml +313 -0
  277. cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_similarity_select_and_insert_strategy_bulk.yaml +550 -0
  278. cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_similarity_strategy.yaml +175 -0
  279. cumulusci/tasks/bulkdata/tests/cassettes/TestSelect.test_select_standard_strategy.yaml +147 -0
  280. cumulusci/tasks/bulkdata/tests/cassettes/TestSnowfakery.test_run_until_records_in_org__multiple_needed.yaml +69 -0
  281. cumulusci/tasks/bulkdata/tests/cassettes/TestSnowfakery.test_run_until_records_in_org__none_needed.yaml +22 -0
  282. cumulusci/tasks/bulkdata/tests/cassettes/TestSnowfakery.test_run_until_records_in_org__one_needed.yaml +24 -0
  283. cumulusci/tasks/bulkdata/tests/cassettes/TestSnowfakery.test_snowfakery_query_salesforce.yaml +25 -0
  284. cumulusci/tasks/bulkdata/tests/cassettes/TestUpdatesIntegrationTests.test_updates_task.yaml +80 -0
  285. cumulusci/tasks/bulkdata/tests/cassettes/TestUpsert.test_simple_upsert__rest.yaml +270 -0
  286. cumulusci/tasks/bulkdata/tests/cassettes/TestUpsert.test_upsert__rest.yaml +267 -0
  287. cumulusci/tasks/bulkdata/tests/cassettes/TestUpsert.test_upsert_complex_external_id_field__rest.yaml +369 -0
  288. cumulusci/tasks/bulkdata/tests/cassettes/TestUpsert.test_upsert_complex_external_id_field_rest__duplicate_error.yaml +204 -0
  289. cumulusci/tasks/bulkdata/tests/cassettes/TestUpsert.test_upsert_complex_fields__bulk.yaml +675 -0
  290. cumulusci/tasks/bulkdata/tests/dummy_data_factory.py +36 -0
  291. cumulusci/tasks/bulkdata/tests/integration_test_utils.py +49 -0
  292. cumulusci/tasks/bulkdata/tests/mapping-oid.yml +87 -0
  293. cumulusci/tasks/bulkdata/tests/mapping_after.yml +38 -0
  294. cumulusci/tasks/bulkdata/tests/mapping_poly.yml +34 -0
  295. cumulusci/tasks/bulkdata/tests/mapping_poly_incomplete.yml +20 -0
  296. cumulusci/tasks/bulkdata/tests/mapping_poly_wrong.yml +21 -0
  297. cumulusci/tasks/bulkdata/tests/mapping_select.yml +20 -0
  298. cumulusci/tasks/bulkdata/tests/mapping_select_invalid_strategy.yml +20 -0
  299. cumulusci/tasks/bulkdata/tests/mapping_select_invalid_threshold__invalid_number.yml +21 -0
  300. cumulusci/tasks/bulkdata/tests/mapping_select_invalid_threshold__invalid_strategy.yml +21 -0
  301. cumulusci/tasks/bulkdata/tests/mapping_select_invalid_threshold__non_float.yml +21 -0
  302. cumulusci/tasks/bulkdata/tests/mapping_select_missing_priority_fields.yml +22 -0
  303. cumulusci/tasks/bulkdata/tests/mapping_select_no_priority_fields.yml +18 -0
  304. cumulusci/tasks/bulkdata/tests/mapping_simple.yml +27 -0
  305. cumulusci/tasks/bulkdata/tests/mapping_v1.yml +28 -0
  306. cumulusci/tasks/bulkdata/tests/mapping_v2.yml +21 -0
  307. cumulusci/tasks/bulkdata/tests/mapping_v3.yml +32 -0
  308. cumulusci/tasks/bulkdata/tests/mapping_vanilla_sf.yml +69 -0
  309. cumulusci/tasks/bulkdata/tests/mock_data_factory_without_mapping.py +12 -0
  310. cumulusci/tasks/bulkdata/tests/person_accounts.yml +23 -0
  311. cumulusci/tasks/bulkdata/tests/person_accounts_minimal.yml +15 -0
  312. cumulusci/tasks/bulkdata/tests/recordtypes.yml +8 -0
  313. cumulusci/tasks/bulkdata/tests/recordtypes_2.yml +6 -0
  314. cumulusci/tasks/bulkdata/tests/recordtypes_with_ispersontype.yml +8 -0
  315. cumulusci/tasks/bulkdata/tests/snowfakery/child/child2.yml +3 -0
  316. cumulusci/tasks/bulkdata/tests/snowfakery/child.yml +4 -0
  317. cumulusci/tasks/bulkdata/tests/snowfakery/gen_npsp_standard_objects.recipe.yml +89 -0
  318. cumulusci/tasks/bulkdata/tests/snowfakery/include_parent.yml +3 -0
  319. cumulusci/tasks/bulkdata/tests/snowfakery/npsp_standard_objects_macros.yml +34 -0
  320. cumulusci/tasks/bulkdata/tests/snowfakery/options.recipe.yml +6 -0
  321. cumulusci/tasks/bulkdata/tests/snowfakery/query_snowfakery.recipe.yml +16 -0
  322. cumulusci/tasks/bulkdata/tests/snowfakery/sf_standard_object_macros.yml +83 -0
  323. cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery.load.yml +2 -0
  324. cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery.recipe.yml +13 -0
  325. cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery_2.load.yml +5 -0
  326. cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery_channels.load.yml +13 -0
  327. cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery_channels.recipe.yml +12 -0
  328. cumulusci/tasks/bulkdata/tests/snowfakery/simple_snowfakery_channels_2.load.yml +13 -0
  329. cumulusci/tasks/bulkdata/tests/snowfakery/unique_values.recipe.yml +4 -0
  330. cumulusci/tasks/bulkdata/tests/snowfakery/upsert.recipe.yml +23 -0
  331. cumulusci/tasks/bulkdata/tests/snowfakery/upsert_2.recipe.yml +29 -0
  332. cumulusci/tasks/bulkdata/tests/snowfakery/upsert_before.yml +10 -0
  333. cumulusci/tasks/bulkdata/tests/test_base_generate_data_tasks.py +61 -0
  334. cumulusci/tasks/bulkdata/tests/test_dates.py +99 -0
  335. cumulusci/tasks/bulkdata/tests/test_delete.py +404 -0
  336. cumulusci/tasks/bulkdata/tests/test_extract.py +1311 -0
  337. cumulusci/tasks/bulkdata/tests/test_factory_utils.py +55 -0
  338. cumulusci/tasks/bulkdata/tests/test_generate_and_load.py +252 -0
  339. cumulusci/tasks/bulkdata/tests/test_generate_from_snowfakery_task.py +343 -0
  340. cumulusci/tasks/bulkdata/tests/test_generatemapping.py +1039 -0
  341. cumulusci/tasks/bulkdata/tests/test_load.py +3175 -0
  342. cumulusci/tasks/bulkdata/tests/test_mapping_parser.py +1658 -0
  343. cumulusci/tasks/bulkdata/tests/test_query_db__joins_self_lookups.yml +12 -0
  344. cumulusci/tasks/bulkdata/tests/test_query_db_joins_lookups.yml +26 -0
  345. cumulusci/tasks/bulkdata/tests/test_query_db_joins_lookups_select.yml +48 -0
  346. cumulusci/tasks/bulkdata/tests/test_select.py +171 -0
  347. cumulusci/tasks/bulkdata/tests/test_select_utils.py +1057 -0
  348. cumulusci/tasks/bulkdata/tests/test_snowfakery.py +1153 -0
  349. cumulusci/tasks/bulkdata/tests/test_step.py +3957 -0
  350. cumulusci/tasks/bulkdata/tests/test_updates.py +513 -0
  351. cumulusci/tasks/bulkdata/tests/test_upsert.py +1015 -0
  352. cumulusci/tasks/bulkdata/tests/test_utils.py +158 -0
  353. cumulusci/tasks/bulkdata/tests/testdata.db +0 -0
  354. cumulusci/tasks/bulkdata/tests/update_describe.py +50 -0
  355. cumulusci/tasks/bulkdata/tests/update_person_accounts.yml +23 -0
  356. cumulusci/tasks/bulkdata/tests/utils.py +114 -0
  357. cumulusci/tasks/bulkdata/update_data.py +260 -0
  358. cumulusci/tasks/bulkdata/upsert_utils.py +130 -0
  359. cumulusci/tasks/bulkdata/utils.py +249 -0
  360. cumulusci/tasks/command.py +178 -0
  361. cumulusci/tasks/connectedapp.py +186 -0
  362. cumulusci/tasks/create_package_version.py +778 -0
  363. cumulusci/tasks/datadictionary.py +745 -0
  364. cumulusci/tasks/dx_convert_from.py +26 -0
  365. cumulusci/tasks/github/__init__.py +17 -0
  366. cumulusci/tasks/github/base.py +16 -0
  367. cumulusci/tasks/github/commit_status.py +13 -0
  368. cumulusci/tasks/github/merge.py +11 -0
  369. cumulusci/tasks/github/publish.py +11 -0
  370. cumulusci/tasks/github/pull_request.py +11 -0
  371. cumulusci/tasks/github/release.py +11 -0
  372. cumulusci/tasks/github/release_report.py +11 -0
  373. cumulusci/tasks/github/tag.py +11 -0
  374. cumulusci/tasks/github/tests/__init__.py +0 -0
  375. cumulusci/tasks/github/tests/test_util.py +202 -0
  376. cumulusci/tasks/github/tests/test_vcs_migration.py +44 -0
  377. cumulusci/tasks/github/tests/util_github_api.py +666 -0
  378. cumulusci/tasks/github/util.py +252 -0
  379. cumulusci/tasks/marketing_cloud/__init__.py +0 -0
  380. cumulusci/tasks/marketing_cloud/api.py +188 -0
  381. cumulusci/tasks/marketing_cloud/base.py +38 -0
  382. cumulusci/tasks/marketing_cloud/deploy.py +345 -0
  383. cumulusci/tasks/marketing_cloud/get_user_info.py +40 -0
  384. cumulusci/tasks/marketing_cloud/mc_constants.py +1 -0
  385. cumulusci/tasks/marketing_cloud/tests/__init__.py +0 -0
  386. cumulusci/tasks/marketing_cloud/tests/conftest.py +46 -0
  387. cumulusci/tasks/marketing_cloud/tests/expected-payload.json +110 -0
  388. cumulusci/tasks/marketing_cloud/tests/test_api.py +97 -0
  389. cumulusci/tasks/marketing_cloud/tests/test_api_soap_envelopes.py +145 -0
  390. cumulusci/tasks/marketing_cloud/tests/test_base.py +14 -0
  391. cumulusci/tasks/marketing_cloud/tests/test_deploy.py +400 -0
  392. cumulusci/tasks/marketing_cloud/tests/test_get_user_info.py +141 -0
  393. cumulusci/tasks/marketing_cloud/tests/validation-response.json +39 -0
  394. cumulusci/tasks/metadata/__init__.py +0 -0
  395. cumulusci/tasks/metadata/ee_src.py +94 -0
  396. cumulusci/tasks/metadata/managed_src.py +100 -0
  397. cumulusci/tasks/metadata/metadata_map.yml +868 -0
  398. cumulusci/tasks/metadata/modify.py +99 -0
  399. cumulusci/tasks/metadata/package.py +684 -0
  400. cumulusci/tasks/metadata/tests/__init__.py +0 -0
  401. cumulusci/tasks/metadata/tests/package_metadata/namespaced_report_folder/.hidden/.keep +0 -0
  402. cumulusci/tasks/metadata/tests/package_metadata/namespaced_report_folder/destructiveChanges.xml +9 -0
  403. cumulusci/tasks/metadata/tests/package_metadata/namespaced_report_folder/package.xml +9 -0
  404. cumulusci/tasks/metadata/tests/package_metadata/namespaced_report_folder/package_install_uninstall.xml +11 -0
  405. cumulusci/tasks/metadata/tests/package_metadata/namespaced_report_folder/reports/namespace__TestFolder/TestReport.report +3 -0
  406. cumulusci/tasks/metadata/tests/sample_package.xml +9 -0
  407. cumulusci/tasks/metadata/tests/test_ee_src.py +112 -0
  408. cumulusci/tasks/metadata/tests/test_managed_src.py +111 -0
  409. cumulusci/tasks/metadata/tests/test_modify.py +123 -0
  410. cumulusci/tasks/metadata/tests/test_package.py +476 -0
  411. cumulusci/tasks/metadata_etl/__init__.py +29 -0
  412. cumulusci/tasks/metadata_etl/base.py +436 -0
  413. cumulusci/tasks/metadata_etl/duplicate_rules.py +24 -0
  414. cumulusci/tasks/metadata_etl/field_sets.py +70 -0
  415. cumulusci/tasks/metadata_etl/help_text.py +92 -0
  416. cumulusci/tasks/metadata_etl/layouts.py +550 -0
  417. cumulusci/tasks/metadata_etl/objects.py +68 -0
  418. cumulusci/tasks/metadata_etl/permissions.py +167 -0
  419. cumulusci/tasks/metadata_etl/picklists.py +221 -0
  420. cumulusci/tasks/metadata_etl/remote_site_settings.py +99 -0
  421. cumulusci/tasks/metadata_etl/sharing.py +138 -0
  422. cumulusci/tasks/metadata_etl/tests/test_base.py +512 -0
  423. cumulusci/tasks/metadata_etl/tests/test_duplicate_rules.py +22 -0
  424. cumulusci/tasks/metadata_etl/tests/test_field_sets.py +156 -0
  425. cumulusci/tasks/metadata_etl/tests/test_help_text.py +387 -0
  426. cumulusci/tasks/metadata_etl/tests/test_ip_ranges.py +85 -0
  427. cumulusci/tasks/metadata_etl/tests/test_layouts.py +858 -0
  428. cumulusci/tasks/metadata_etl/tests/test_objects.py +236 -0
  429. cumulusci/tasks/metadata_etl/tests/test_permissions.py +223 -0
  430. cumulusci/tasks/metadata_etl/tests/test_picklists.py +547 -0
  431. cumulusci/tasks/metadata_etl/tests/test_remote_site_settings.py +46 -0
  432. cumulusci/tasks/metadata_etl/tests/test_sharing.py +333 -0
  433. cumulusci/tasks/metadata_etl/tests/test_value_sets.py +298 -0
  434. cumulusci/tasks/metadata_etl/value_sets.py +106 -0
  435. cumulusci/tasks/metadeploy.py +393 -0
  436. cumulusci/tasks/metaxml.py +88 -0
  437. cumulusci/tasks/preflight/__init__.py +0 -0
  438. cumulusci/tasks/preflight/dataset_load.py +49 -0
  439. cumulusci/tasks/preflight/licenses.py +86 -0
  440. cumulusci/tasks/preflight/packages.py +14 -0
  441. cumulusci/tasks/preflight/permsets.py +23 -0
  442. cumulusci/tasks/preflight/recordtypes.py +16 -0
  443. cumulusci/tasks/preflight/retrieve_tasks.py +30 -0
  444. cumulusci/tasks/preflight/settings.py +77 -0
  445. cumulusci/tasks/preflight/sobjects.py +202 -0
  446. cumulusci/tasks/preflight/tests/test_dataset_load.py +85 -0
  447. cumulusci/tasks/preflight/tests/test_licenses.py +174 -0
  448. cumulusci/tasks/preflight/tests/test_packages.py +14 -0
  449. cumulusci/tasks/preflight/tests/test_permset_preflights.py +51 -0
  450. cumulusci/tasks/preflight/tests/test_recordtypes.py +30 -0
  451. cumulusci/tasks/preflight/tests/test_retrieve_tasks.py +62 -0
  452. cumulusci/tasks/preflight/tests/test_settings.py +130 -0
  453. cumulusci/tasks/preflight/tests/test_sobjects.py +231 -0
  454. cumulusci/tasks/push/README.md +59 -0
  455. cumulusci/tasks/push/__init__.py +0 -0
  456. cumulusci/tasks/push/push_api.py +659 -0
  457. cumulusci/tasks/push/pushfails.py +136 -0
  458. cumulusci/tasks/push/tasks.py +476 -0
  459. cumulusci/tasks/push/tests/conftest.py +263 -0
  460. cumulusci/tasks/push/tests/test_push_api.py +951 -0
  461. cumulusci/tasks/push/tests/test_push_tasks.py +659 -0
  462. cumulusci/tasks/release_notes/README.md +63 -0
  463. cumulusci/tasks/release_notes/__init__.py +0 -0
  464. cumulusci/tasks/release_notes/exceptions.py +5 -0
  465. cumulusci/tasks/release_notes/generator.py +137 -0
  466. cumulusci/tasks/release_notes/parser.py +232 -0
  467. cumulusci/tasks/release_notes/provider.py +44 -0
  468. cumulusci/tasks/release_notes/task.py +300 -0
  469. cumulusci/tasks/release_notes/tests/__init__.py +0 -0
  470. cumulusci/tasks/release_notes/tests/change_notes/full/example1.md +17 -0
  471. cumulusci/tasks/release_notes/tests/change_notes/multi/1.txt +1 -0
  472. cumulusci/tasks/release_notes/tests/change_notes/multi/2.txt +1 -0
  473. cumulusci/tasks/release_notes/tests/change_notes/multi/3.txt +1 -0
  474. cumulusci/tasks/release_notes/tests/change_notes/single/1.txt +1 -0
  475. cumulusci/tasks/release_notes/tests/test_generator.py +582 -0
  476. cumulusci/tasks/release_notes/tests/test_parser.py +867 -0
  477. cumulusci/tasks/release_notes/tests/test_provider.py +512 -0
  478. cumulusci/tasks/release_notes/tests/test_task.py +461 -0
  479. cumulusci/tasks/release_notes/tests/utils.py +153 -0
  480. cumulusci/tasks/robotframework/__init__.py +3 -0
  481. cumulusci/tasks/robotframework/debugger/DebugListener.py +100 -0
  482. cumulusci/tasks/robotframework/debugger/__init__.py +10 -0
  483. cumulusci/tasks/robotframework/debugger/model.py +87 -0
  484. cumulusci/tasks/robotframework/debugger/ui.py +259 -0
  485. cumulusci/tasks/robotframework/libdoc.py +269 -0
  486. cumulusci/tasks/robotframework/robotframework.py +392 -0
  487. cumulusci/tasks/robotframework/stylesheet.css +130 -0
  488. cumulusci/tasks/robotframework/template.html +109 -0
  489. cumulusci/tasks/robotframework/tests/TestLibrary.py +18 -0
  490. cumulusci/tasks/robotframework/tests/TestPageObjects.py +31 -0
  491. cumulusci/tasks/robotframework/tests/TestResource.robot +8 -0
  492. cumulusci/tasks/robotframework/tests/failing_tests.robot +16 -0
  493. cumulusci/tasks/robotframework/tests/performance.robot +23 -0
  494. cumulusci/tasks/robotframework/tests/test_browser_proxies.py +137 -0
  495. cumulusci/tasks/robotframework/tests/test_debugger.py +360 -0
  496. cumulusci/tasks/robotframework/tests/test_robot_parallel.py +141 -0
  497. cumulusci/tasks/robotframework/tests/test_robotframework.py +860 -0
  498. cumulusci/tasks/salesforce/BaseRetrieveMetadata.py +58 -0
  499. cumulusci/tasks/salesforce/BaseSalesforceApiTask.py +45 -0
  500. cumulusci/tasks/salesforce/BaseSalesforceMetadataApiTask.py +18 -0
  501. cumulusci/tasks/salesforce/BaseSalesforceTask.py +4 -0
  502. cumulusci/tasks/salesforce/BaseUninstallMetadata.py +41 -0
  503. cumulusci/tasks/salesforce/CreateCommunity.py +124 -0
  504. cumulusci/tasks/salesforce/CreatePackage.py +29 -0
  505. cumulusci/tasks/salesforce/Deploy.py +240 -0
  506. cumulusci/tasks/salesforce/DeployBundles.py +88 -0
  507. cumulusci/tasks/salesforce/DescribeMetadataTypes.py +26 -0
  508. cumulusci/tasks/salesforce/EnsureRecordTypes.py +202 -0
  509. cumulusci/tasks/salesforce/GetInstalledPackages.py +8 -0
  510. cumulusci/tasks/salesforce/ListCommunities.py +40 -0
  511. cumulusci/tasks/salesforce/ListCommunityTemplates.py +19 -0
  512. cumulusci/tasks/salesforce/PublishCommunity.py +62 -0
  513. cumulusci/tasks/salesforce/RetrievePackaged.py +41 -0
  514. cumulusci/tasks/salesforce/RetrieveReportsAndDashboards.py +82 -0
  515. cumulusci/tasks/salesforce/RetrieveUnpackaged.py +36 -0
  516. cumulusci/tasks/salesforce/SOQLQuery.py +39 -0
  517. cumulusci/tasks/salesforce/UninstallLocal.py +15 -0
  518. cumulusci/tasks/salesforce/UninstallLocalBundles.py +28 -0
  519. cumulusci/tasks/salesforce/UninstallLocalNamespacedBundles.py +58 -0
  520. cumulusci/tasks/salesforce/UninstallPackage.py +32 -0
  521. cumulusci/tasks/salesforce/UninstallPackaged.py +56 -0
  522. cumulusci/tasks/salesforce/UpdateAdminProfile.py +8 -0
  523. cumulusci/tasks/salesforce/__init__.py +79 -0
  524. cumulusci/tasks/salesforce/activate_flow.py +74 -0
  525. cumulusci/tasks/salesforce/check_components.py +324 -0
  526. cumulusci/tasks/salesforce/composite.py +142 -0
  527. cumulusci/tasks/salesforce/create_permission_sets.py +35 -0
  528. cumulusci/tasks/salesforce/custom_settings.py +134 -0
  529. cumulusci/tasks/salesforce/custom_settings_wait.py +132 -0
  530. cumulusci/tasks/salesforce/enable_prediction.py +107 -0
  531. cumulusci/tasks/salesforce/insert_record.py +40 -0
  532. cumulusci/tasks/salesforce/install_package_version.py +242 -0
  533. cumulusci/tasks/salesforce/license_preflights.py +8 -0
  534. cumulusci/tasks/salesforce/network_member_group.py +178 -0
  535. cumulusci/tasks/salesforce/nonsourcetracking.py +228 -0
  536. cumulusci/tasks/salesforce/org_settings.py +193 -0
  537. cumulusci/tasks/salesforce/package_upload.py +328 -0
  538. cumulusci/tasks/salesforce/profiles.py +74 -0
  539. cumulusci/tasks/salesforce/promote_package_version.py +376 -0
  540. cumulusci/tasks/salesforce/retrieve_profile.py +195 -0
  541. cumulusci/tasks/salesforce/salesforce_files.py +244 -0
  542. cumulusci/tasks/salesforce/sourcetracking.py +507 -0
  543. cumulusci/tasks/salesforce/tests/__init__.py +3 -0
  544. cumulusci/tasks/salesforce/tests/test_CreateCommunity.py +278 -0
  545. cumulusci/tasks/salesforce/tests/test_CreatePackage.py +22 -0
  546. cumulusci/tasks/salesforce/tests/test_Deploy.py +470 -0
  547. cumulusci/tasks/salesforce/tests/test_DeployBundles.py +76 -0
  548. cumulusci/tasks/salesforce/tests/test_EnsureRecordTypes.py +345 -0
  549. cumulusci/tasks/salesforce/tests/test_ListCommunities.py +84 -0
  550. cumulusci/tasks/salesforce/tests/test_ListCommunityTemplates.py +49 -0
  551. cumulusci/tasks/salesforce/tests/test_PackageUpload.py +547 -0
  552. cumulusci/tasks/salesforce/tests/test_ProfileGrantAllAccess.py +699 -0
  553. cumulusci/tasks/salesforce/tests/test_PublishCommunity.py +181 -0
  554. cumulusci/tasks/salesforce/tests/test_RetrievePackaged.py +24 -0
  555. cumulusci/tasks/salesforce/tests/test_RetrieveReportsAndDashboards.py +56 -0
  556. cumulusci/tasks/salesforce/tests/test_RetrieveUnpackaged.py +21 -0
  557. cumulusci/tasks/salesforce/tests/test_SOQLQuery.py +30 -0
  558. cumulusci/tasks/salesforce/tests/test_UninstallLocal.py +15 -0
  559. cumulusci/tasks/salesforce/tests/test_UninstallLocalBundles.py +19 -0
  560. cumulusci/tasks/salesforce/tests/test_UninstallLocalNamespacedBundles.py +22 -0
  561. cumulusci/tasks/salesforce/tests/test_UninstallPackage.py +19 -0
  562. cumulusci/tasks/salesforce/tests/test_UninstallPackaged.py +66 -0
  563. cumulusci/tasks/salesforce/tests/test_UninstallPackagedIncremental.py +127 -0
  564. cumulusci/tasks/salesforce/tests/test_activate_flow.py +132 -0
  565. cumulusci/tasks/salesforce/tests/test_base_tasks.py +110 -0
  566. cumulusci/tasks/salesforce/tests/test_check_components.py +445 -0
  567. cumulusci/tasks/salesforce/tests/test_composite.py +250 -0
  568. cumulusci/tasks/salesforce/tests/test_create_permission_sets.py +41 -0
  569. cumulusci/tasks/salesforce/tests/test_custom_settings.py +227 -0
  570. cumulusci/tasks/salesforce/tests/test_custom_settings_wait.py +174 -0
  571. cumulusci/tasks/salesforce/tests/test_describemetadatatypes.py +18 -0
  572. cumulusci/tasks/salesforce/tests/test_enable_prediction.py +240 -0
  573. cumulusci/tasks/salesforce/tests/test_insert_record.py +110 -0
  574. cumulusci/tasks/salesforce/tests/test_install_package_version.py +464 -0
  575. cumulusci/tasks/salesforce/tests/test_network_member_group.py +444 -0
  576. cumulusci/tasks/salesforce/tests/test_nonsourcetracking.py +235 -0
  577. cumulusci/tasks/salesforce/tests/test_org_settings.py +407 -0
  578. cumulusci/tasks/salesforce/tests/test_profiles.py +202 -0
  579. cumulusci/tasks/salesforce/tests/test_retrieve_profile.py +287 -0
  580. cumulusci/tasks/salesforce/tests/test_salesforce_files.py +228 -0
  581. cumulusci/tasks/salesforce/tests/test_sourcetracking.py +350 -0
  582. cumulusci/tasks/salesforce/tests/test_trigger_handlers.py +300 -0
  583. cumulusci/tasks/salesforce/tests/test_update_dependencies.py +509 -0
  584. cumulusci/tasks/salesforce/tests/util.py +79 -0
  585. cumulusci/tasks/salesforce/trigger_handlers.py +119 -0
  586. cumulusci/tasks/salesforce/uninstall_packaged_incremental.py +136 -0
  587. cumulusci/tasks/salesforce/update_dependencies.py +290 -0
  588. cumulusci/tasks/salesforce/update_profile.py +339 -0
  589. cumulusci/tasks/salesforce/users/permsets.py +227 -0
  590. cumulusci/tasks/salesforce/users/photos.py +162 -0
  591. cumulusci/tasks/salesforce/users/tests/photo.mock.txt +1 -0
  592. cumulusci/tasks/salesforce/users/tests/test_permsets.py +950 -0
  593. cumulusci/tasks/salesforce/users/tests/test_photos.py +373 -0
  594. cumulusci/tasks/sample_data/capture_sample_data.py +77 -0
  595. cumulusci/tasks/sample_data/load_sample_data.py +85 -0
  596. cumulusci/tasks/sample_data/test_capture_sample_data.py +117 -0
  597. cumulusci/tasks/sample_data/test_load_sample_data.py +121 -0
  598. cumulusci/tasks/sfdx.py +83 -0
  599. cumulusci/tasks/tests/__init__.py +1 -0
  600. cumulusci/tasks/tests/conftest.py +30 -0
  601. cumulusci/tasks/tests/test_command.py +129 -0
  602. cumulusci/tasks/tests/test_connectedapp.py +236 -0
  603. cumulusci/tasks/tests/test_create_package_version.py +847 -0
  604. cumulusci/tasks/tests/test_datadictionary.py +1575 -0
  605. cumulusci/tasks/tests/test_dx_convert_from.py +60 -0
  606. cumulusci/tasks/tests/test_metadeploy.py +624 -0
  607. cumulusci/tasks/tests/test_metaxml.py +99 -0
  608. cumulusci/tasks/tests/test_promote_package_version.py +488 -0
  609. cumulusci/tasks/tests/test_pushfails.py +96 -0
  610. cumulusci/tasks/tests/test_salesforce.py +72 -0
  611. cumulusci/tasks/tests/test_sfdx.py +105 -0
  612. cumulusci/tasks/tests/test_util.py +207 -0
  613. cumulusci/tasks/util.py +261 -0
  614. cumulusci/tasks/vcs/__init__.py +19 -0
  615. cumulusci/tasks/vcs/commit_status.py +58 -0
  616. cumulusci/tasks/vcs/create_commit_status.py +37 -0
  617. cumulusci/tasks/vcs/download_extract.py +199 -0
  618. cumulusci/tasks/vcs/merge.py +298 -0
  619. cumulusci/tasks/vcs/publish.py +207 -0
  620. cumulusci/tasks/vcs/pull_request.py +9 -0
  621. cumulusci/tasks/vcs/release.py +134 -0
  622. cumulusci/tasks/vcs/release_report.py +105 -0
  623. cumulusci/tasks/vcs/tag.py +31 -0
  624. cumulusci/tasks/vcs/tests/github/test_commit_status.py +196 -0
  625. cumulusci/tasks/vcs/tests/github/test_download_extract.py +896 -0
  626. cumulusci/tasks/vcs/tests/github/test_merge.py +1118 -0
  627. cumulusci/tasks/vcs/tests/github/test_publish.py +823 -0
  628. cumulusci/tasks/vcs/tests/github/test_pull_request.py +29 -0
  629. cumulusci/tasks/vcs/tests/github/test_release.py +390 -0
  630. cumulusci/tasks/vcs/tests/github/test_release_report.py +109 -0
  631. cumulusci/tasks/vcs/tests/github/test_tag.py +90 -0
  632. cumulusci/tasks/vlocity/exceptions.py +2 -0
  633. cumulusci/tasks/vlocity/tests/test_vlocity.py +283 -0
  634. cumulusci/tasks/vlocity/vlocity.py +342 -0
  635. cumulusci/tests/__init__.py +1 -0
  636. cumulusci/tests/cassettes/GET_sobjects_Account_PersonAccount_describe.yaml +18 -0
  637. cumulusci/tests/cassettes/TestIntegrationInfrastructure.test_integration_tests.yaml +19 -0
  638. cumulusci/tests/pytest_plugins/pytest_sf_orgconnect.py +307 -0
  639. cumulusci/tests/pytest_plugins/pytest_sf_vcr.py +275 -0
  640. cumulusci/tests/pytest_plugins/pytest_sf_vcr_serializer.py +160 -0
  641. cumulusci/tests/pytest_plugins/pytest_typeguard.py +5 -0
  642. cumulusci/tests/pytest_plugins/test_vcr_string_compressor.py +49 -0
  643. cumulusci/tests/pytest_plugins/vcr_string_compressor.py +97 -0
  644. cumulusci/tests/shared_cassettes/GET_sobjects_Account_describe.yaml +18 -0
  645. cumulusci/tests/shared_cassettes/GET_sobjects_Case_describe.yaml +18 -0
  646. cumulusci/tests/shared_cassettes/GET_sobjects_Contact_describe.yaml +4838 -0
  647. cumulusci/tests/shared_cassettes/GET_sobjects_Custom__c_describe.yaml +242 -0
  648. cumulusci/tests/shared_cassettes/GET_sobjects_Event_describe.yaml +19 -0
  649. cumulusci/tests/shared_cassettes/GET_sobjects_Global_describe.yaml +1338 -0
  650. cumulusci/tests/shared_cassettes/GET_sobjects_Lead_describe.yaml +18 -0
  651. cumulusci/tests/shared_cassettes/GET_sobjects_OpportunityContactRole_describe.yaml +34 -0
  652. cumulusci/tests/shared_cassettes/GET_sobjects_Opportunity_describe.yaml +1261 -0
  653. cumulusci/tests/shared_cassettes/GET_sobjects_Organization.yaml +49 -0
  654. cumulusci/tests/shared_cassettes/vcr_string_templates/batchInfoList_xml.tpl +15 -0
  655. cumulusci/tests/shared_cassettes/vcr_string_templates/batchInfo_xml.tpl +13 -0
  656. cumulusci/tests/shared_cassettes/vcr_string_templates/jobInfo_insert_xml.tpl +24 -0
  657. cumulusci/tests/shared_cassettes/vcr_string_templates/jobInfo_upsert_xml.tpl +25 -0
  658. cumulusci/tests/test_entry_points.py +20 -0
  659. cumulusci/tests/test_integration_infrastructure.py +131 -0
  660. cumulusci/tests/test_main.py +9 -0
  661. cumulusci/tests/test_schema.py +32 -0
  662. cumulusci/tests/test_utils.py +657 -0
  663. cumulusci/tests/test_vcr_serializer.py +134 -0
  664. cumulusci/tests/uncompressed_cassette.yaml +83 -0
  665. cumulusci/tests/util.py +344 -0
  666. cumulusci/utils/__init__.py +731 -0
  667. cumulusci/utils/classutils.py +9 -0
  668. cumulusci/utils/collections.py +32 -0
  669. cumulusci/utils/deprecation.py +11 -0
  670. cumulusci/utils/encryption.py +31 -0
  671. cumulusci/utils/fileutils.py +295 -0
  672. cumulusci/utils/git.py +142 -0
  673. cumulusci/utils/http/multi_request.py +214 -0
  674. cumulusci/utils/http/requests_utils.py +103 -0
  675. cumulusci/utils/http/tests/cassettes/ManualEditTestCompositeParallelSalesforce.test_http_headers.yaml +32 -0
  676. cumulusci/utils/http/tests/cassettes/TestCompositeParallelSalesforce.test_composite_parallel_salesforce.yaml +65 -0
  677. cumulusci/utils/http/tests/cassettes/TestCompositeParallelSalesforce.test_errors.yaml +24 -0
  678. cumulusci/utils/http/tests/cassettes/TestCompositeParallelSalesforce.test_reference_ids.yaml +49 -0
  679. cumulusci/utils/http/tests/test_multi_request.py +255 -0
  680. cumulusci/utils/iterators.py +21 -0
  681. cumulusci/utils/logging.py +128 -0
  682. cumulusci/utils/metaprogramming.py +10 -0
  683. cumulusci/utils/options.py +138 -0
  684. cumulusci/utils/parallel/queries_in_parallel/run_queries_in_parallel.py +29 -0
  685. cumulusci/utils/parallel/queries_in_parallel/tests/test_run_queries_in_parallel.py +50 -0
  686. cumulusci/utils/parallel/task_worker_queues/parallel_worker.py +238 -0
  687. cumulusci/utils/parallel/task_worker_queues/parallel_worker_queue.py +243 -0
  688. cumulusci/utils/parallel/task_worker_queues/tests/test_parallel_worker.py +353 -0
  689. cumulusci/utils/salesforce/count_sobjects.py +46 -0
  690. cumulusci/utils/salesforce/soql.py +17 -0
  691. cumulusci/utils/salesforce/tests/cassettes/ManualEdit_TestCountSObjects.test_count_sobjects__network_errors.yaml +23 -0
  692. cumulusci/utils/salesforce/tests/cassettes/TestCountSObjects.test_count_sobjects__errors.yaml +33 -0
  693. cumulusci/utils/salesforce/tests/cassettes/TestCountSObjects.test_count_sobjects_simple.yaml +29 -0
  694. cumulusci/utils/salesforce/tests/test_count_sobjects.py +29 -0
  695. cumulusci/utils/salesforce/tests/test_soql.py +30 -0
  696. cumulusci/utils/tests/cassettes/ManualEditTestDescribeOrg.test_minimal_schema.yaml +36 -0
  697. cumulusci/utils/tests/cassettes/ManualEdit_test_describe_to_sql.yaml +191 -0
  698. cumulusci/utils/tests/test_fileutils.py +284 -0
  699. cumulusci/utils/tests/test_git.py +85 -0
  700. cumulusci/utils/tests/test_logging.py +70 -0
  701. cumulusci/utils/tests/test_option_parsing.py +188 -0
  702. cumulusci/utils/tests/test_org_schema.py +691 -0
  703. cumulusci/utils/tests/test_org_schema_models.py +79 -0
  704. cumulusci/utils/tests/test_waiting.py +25 -0
  705. cumulusci/utils/version_strings.py +391 -0
  706. cumulusci/utils/waiting.py +42 -0
  707. cumulusci/utils/xml/__init__.py +91 -0
  708. cumulusci/utils/xml/metadata_tree.py +299 -0
  709. cumulusci/utils/xml/robot_xml.py +114 -0
  710. cumulusci/utils/xml/salesforce_encoding.py +100 -0
  711. cumulusci/utils/xml/test/test_metadata_tree.py +251 -0
  712. cumulusci/utils/xml/test/test_salesforce_encoding.py +173 -0
  713. cumulusci/utils/yaml/cumulusci_yml.py +401 -0
  714. cumulusci/utils/yaml/model_parser.py +156 -0
  715. cumulusci/utils/yaml/safer_loader.py +74 -0
  716. cumulusci/utils/yaml/tests/bad_cci.yml +5 -0
  717. cumulusci/utils/yaml/tests/cassettes/TestCumulusciYml.test_validate_url__with_errors.yaml +20 -0
  718. cumulusci/utils/yaml/tests/test_cumulusci_yml.py +286 -0
  719. cumulusci/utils/yaml/tests/test_model_parser.py +175 -0
  720. cumulusci/utils/yaml/tests/test_safer_loader.py +88 -0
  721. cumulusci/utils/ziputils.py +61 -0
  722. cumulusci/vcs/base.py +143 -0
  723. cumulusci/vcs/bootstrap.py +272 -0
  724. cumulusci/vcs/github/__init__.py +24 -0
  725. cumulusci/vcs/github/adapter.py +689 -0
  726. cumulusci/vcs/github/release_notes/generator.py +219 -0
  727. cumulusci/vcs/github/release_notes/parser.py +151 -0
  728. cumulusci/vcs/github/release_notes/provider.py +143 -0
  729. cumulusci/vcs/github/service.py +569 -0
  730. cumulusci/vcs/github/tests/test_adapter.py +138 -0
  731. cumulusci/vcs/github/tests/test_service.py +408 -0
  732. cumulusci/vcs/models.py +586 -0
  733. cumulusci/vcs/tests/conftest.py +41 -0
  734. cumulusci/vcs/tests/dummy_service.py +241 -0
  735. cumulusci/vcs/tests/test_vcs_base.py +687 -0
  736. cumulusci/vcs/tests/test_vcs_bootstrap.py +727 -0
  737. cumulusci/vcs/utils/__init__.py +31 -0
  738. cumulusci/vcs/vcs_source.py +287 -0
  739. cumulusci_plus-5.0.0.dist-info/METADATA +145 -0
  740. cumulusci_plus-5.0.0.dist-info/RECORD +744 -0
  741. cumulusci_plus-5.0.0.dist-info/WHEEL +4 -0
  742. cumulusci_plus-5.0.0.dist-info/entry_points.txt +3 -0
  743. cumulusci_plus-5.0.0.dist-info/licenses/AUTHORS.rst +41 -0
  744. cumulusci_plus-5.0.0.dist-info/licenses/LICENSE +30 -0
@@ -0,0 +1,433 @@
1
+ # Note: Unlike in traditional robot libraries, this docstring will end
2
+ # up in output from the libdoc task. For that to happen, it must be
3
+ # before the imports.
4
+
5
+ """
6
+ The following page objects are automatically included when
7
+ importing the PageObject library. You should not directly import this
8
+ file.
9
+
10
+ """
11
+
12
+ import re
13
+
14
+ from selenium.common.exceptions import NoSuchElementException, TimeoutException
15
+ from SeleniumLibrary.errors import ElementNotFound
16
+
17
+ from cumulusci.robotframework.form_handlers import get_form_handler
18
+ from cumulusci.robotframework.pageobjects import BasePage, pageobject
19
+ from cumulusci.robotframework.utils import capture_screenshot_on_error
20
+
21
+ # This will appear in the generated documentation in place of
22
+ # the filename.
23
+ TITLE = "Base Page Objects"
24
+
25
+
26
+ @pageobject(page_type="Listing")
27
+ class ListingPage(BasePage):
28
+ """Page object representing a Listing page
29
+
30
+ When going to the Listing page, you need to specify the object name. You
31
+ may also specify the name of a filter.
32
+
33
+ Example
34
+
35
+ | Go to page Listing Contact filterName=Recent
36
+
37
+ """
38
+
39
+ def _go_to_page(self, filter_name=None, locator=None):
40
+ url_template = "{root}/lightning/o/{object_name}/list"
41
+ url = url_template.format(
42
+ root=self.cumulusci.org.lightning_base_url, object_name=self.object_name
43
+ )
44
+ if filter_name:
45
+ url += "?filterName={}".format(filter_name)
46
+ self.selenium.go_to(url)
47
+ self.salesforce.wait_until_loading_is_complete(locator=locator)
48
+
49
+ def _is_current_page(self):
50
+ self.selenium.location_should_contain(
51
+ "/lightning/o/{}/list".format(self.object_name)
52
+ )
53
+
54
+ @capture_screenshot_on_error
55
+ def select_rows(self, *items):
56
+ """Check the checkbutton for one or more rows
57
+
58
+ Arguments are one or more strings. Each row that contains one
59
+ of the strings in any column will be clicked. Rows that have
60
+ already been checked will remain checked.
61
+
62
+ If no elements are found to match, this keyword will raise an error.
63
+
64
+ Example
65
+
66
+ The following example selects all rows that contain either
67
+ John Doe or Jane Doe in any column.
68
+
69
+ | Select Rows John Doe Jane Doe
70
+ """
71
+ for item in items:
72
+ xpath = self.salesforce.get_locator("object_list.checkbutton", item)
73
+ elements = self.selenium.get_webelements(xpath)
74
+ if elements:
75
+ for element in elements:
76
+ cb = element.find_element_by_tag_name("input")
77
+ if not cb.is_selected():
78
+ element.click()
79
+ else:
80
+ raise Exception(f"No rows matched '{item}'")
81
+
82
+ @capture_screenshot_on_error
83
+ def deselect_rows(self, *items):
84
+ """Uncheck the checkbutton for one or more rows
85
+
86
+ Arguments are one or more strings. Each row that contains one
87
+ of the strings in any column will be delselected. Rows that are
88
+ unchecked will remain unchecked.
89
+
90
+ If no elements are found to match, this keyword will raise an error.
91
+
92
+ Example
93
+
94
+ The following example deselects all rows that contain either
95
+ John Doe or Jane Doe in any column.
96
+
97
+ | Select Rows John Doe Jane Doe
98
+
99
+ """
100
+ for item in items:
101
+ xpath = self.salesforce.get_locator("object_list.checkbutton", item)
102
+ elements = self.selenium.get_webelements(xpath)
103
+
104
+ if elements:
105
+ for element in elements:
106
+ cb = element.find_element_by_tag_name("input")
107
+ if cb.is_selected():
108
+ self.builtin.log(f"clicking on element for {item}")
109
+ element.click()
110
+ else:
111
+ self.builtin.log(f"NOT clicking on element for {item}")
112
+ else:
113
+ raise Exception(f"No rows matched '{item}'")
114
+
115
+
116
+ class ModalMixin:
117
+ def _wait_to_appear(self, expected_heading=None):
118
+ """Waits until the modal is visible"""
119
+ locator = "//div[contains(@class, 'uiModal')]"
120
+ if expected_heading:
121
+ locator += f"//h2[text()='{expected_heading}']"
122
+ error = f"A modal with the heading {expected_heading} did not appear before the timeout"
123
+ else:
124
+ error = "The modal did not appear before the timeout"
125
+
126
+ self.salesforce.wait_for_aura()
127
+ self.selenium.wait_until_element_is_visible(locator, error=error)
128
+
129
+ @capture_screenshot_on_error
130
+ def close_the_modal(self):
131
+ """Closes the open modal"""
132
+
133
+ locator = "css: button.slds-modal__close"
134
+ self.selenium.wait_until_element_is_enabled(locator)
135
+ self.selenium.click_element(locator)
136
+ self.wait_until_modal_is_closed()
137
+ self._remove_from_library_search_order()
138
+
139
+ @capture_screenshot_on_error
140
+ def click_modal_button(self, button_label):
141
+ """Click the named modal button (Save, Save & New, Cancel, etc)"""
142
+ # stolen from Salesforce.py:click_modal_button
143
+ locator = f"sf:modal.button:{button_label}"
144
+ self.selenium.wait_until_page_contains_element(locator)
145
+ self.selenium.wait_until_element_is_enabled(locator)
146
+ self.salesforce._jsclick(locator)
147
+
148
+ @capture_screenshot_on_error
149
+ def modal_should_contain_errors(self, *messages):
150
+ """Verify that the modal contains the following errors
151
+
152
+ This will look for the given message in the standard SLDS
153
+ component (<ul class='errorsList'>)
154
+ """
155
+ for message in messages:
156
+ locator = "//ul[@class='errorsList']//li[contains(., \"{}\")]".format(
157
+ message
158
+ )
159
+ self.selenium.page_should_contain_element(
160
+ locator,
161
+ 'The page did not contain an error with the text "{}"'.format(message),
162
+ )
163
+
164
+ @capture_screenshot_on_error
165
+ def modal_should_show_edit_error_for_fields(self, *field_names):
166
+ """Verify that a dialog is showing requiring a review of the given fields
167
+
168
+ This works by looking for a the "we hit a snag" popup, and
169
+ then looking for an anchor tag with the attribute
170
+ force-recordediterror_recordediterror, along with the given
171
+ text.
172
+
173
+ """
174
+ self.selenium.wait_until_page_contains_element("sf:modal.field_alert")
175
+ for field_name in field_names:
176
+ locator = f"sf:modal.review_alert:{field_name}"
177
+ self.selenium.page_should_contain_element(
178
+ locator, f"Unable to find alert with field '{field_name}'"
179
+ )
180
+
181
+ @capture_screenshot_on_error
182
+ def populate_field(self, name, value):
183
+ """Populate a field on the modal form
184
+
185
+ Name must the the label of a field as it appears on the modal form.
186
+
187
+ Example
188
+
189
+ | Populate field First Name Connor
190
+ | Populate field Last Name MacLeod
191
+ """
192
+ # For now, call the same keyword in Salesforce.py. Eventually
193
+ # that keyword may get moved here and deprecated from that
194
+ # library.
195
+ self.salesforce.populate_field(name, value)
196
+
197
+ @capture_screenshot_on_error
198
+ def populate_form(self, *args, **kwargs):
199
+ """Populate the modal form
200
+
201
+ Arguments are of the form key=value, where 'key' represents
202
+ a field name as it appears on the form (specifically, the text
203
+ of a label with the class 'uiLabel').
204
+
205
+ Example:
206
+
207
+ | Populate form
208
+ | ... First Name=Connor
209
+ | ... Last Name=MacLeod
210
+ """
211
+ # For now, call the same keyword in Salesforce.py. Eventually
212
+ # that keyword may get moved here and deprecated from that
213
+ # library.
214
+ self.salesforce.populate_form(*args, **kwargs)
215
+
216
+ @capture_screenshot_on_error
217
+ def select_dropdown_value(self, label, value):
218
+ """Sets the value of a dropdown form field from one of the values in the dropdown
219
+
220
+ ``label`` represents the label on the form field (eg: Lead Source)
221
+
222
+ If a modal is present, the modal will be searched for the dropdown. Otherwise
223
+ the first matching dropdown on the entire web page will be used.
224
+ """
225
+ locator = f"label:{label}"
226
+ try:
227
+ element = self.selenium.get_webelement(locator)
228
+ except (NoSuchElementException, TimeoutException, ElementNotFound):
229
+ raise ElementNotFound(f"Form element with label '{label}' was not found")
230
+
231
+ self.salesforce.scroll_element_into_view(locator)
232
+ handler = get_form_handler(element, locator)
233
+ try:
234
+ handler.set(value)
235
+ except (NoSuchElementException, TimeoutException, ElementNotFound):
236
+ raise ElementNotFound(f"Dropdown value '{value}' not found")
237
+
238
+ @capture_screenshot_on_error
239
+ def wait_until_modal_is_closed(self, timeout=None):
240
+ """Waits until the modal is no longer visible
241
+
242
+ If the modal isn't open, this will not throw an error.
243
+ """
244
+ locator = "//div[contains(@class, 'uiModal')]"
245
+
246
+ self.selenium.wait_until_page_does_not_contain_element(locator)
247
+
248
+ def _get_form_element_for_label(self, label):
249
+ """Returns an element of class 'slds-form-element' which contains the given label.
250
+
251
+ If you use this to find an item on a modal, you're responsible for waiting for the
252
+ modal to appear before calling this function.
253
+ """
254
+ # search from the root of the document, unless a modal
255
+ # is open
256
+ root = self.selenium.driver.find_element_by_tag_name("body")
257
+ with self._no_implicit_wait():
258
+ # We don't want to wait, we just want to know if the
259
+ # modal is alredy there or not. The caller should have
260
+ # already waited for the modal.
261
+
262
+ # also, we use find_elements (plural) here because it will
263
+ # return an empty list rather than throwing an error
264
+ modals = root.find_elements_by_xpath("//div[contains(@class, 'uiModal')]")
265
+ # There should only ever be zero or one, but the Salesforce
266
+ # UI never ceases to surprise me.
267
+ modals = [m for m in modals if m.is_displayed()]
268
+ if modals:
269
+ root = modals[0]
270
+ try:
271
+ # As salesforce evolves, more and more fields use <label for='some-id'>
272
+ # where "for" points to the associated input field. w00t! If we can,
273
+ # use that. If not, fall back to an older strategy
274
+ try:
275
+ label_element = root.find_element_by_xpath(f'//label[text()="{label}"]')
276
+ input_id = label_element.get_attribute("for")
277
+ element = root.find_element_by_id(input_id)
278
+ return element
279
+
280
+ except NoSuchElementException:
281
+ pass
282
+
283
+ # gnarly, but effective.
284
+ # this finds an element with the class slds-form-element which
285
+ # has a child element with the class 'form-element__label' and
286
+ # text that matches the given label.
287
+ locator = f".//*[contains(@class, 'slds-form-element') and .//*[contains(@class, 'form-element__label')]/descendant-or-self::text()='{label}']"
288
+ element = root.find_element_by_xpath(locator)
289
+ return element
290
+
291
+ except NoSuchElementException:
292
+ raise ElementNotFound(f"Form element with label '{label}' was not found")
293
+
294
+
295
+ @pageobject("New")
296
+ class NewModal(ModalMixin, BasePage):
297
+ """A page object representing the New Object modal
298
+
299
+ Note: You should not use this page object with 'Go to page'. Instead,
300
+ you can use 'Wait for modal to appear' after performing an action
301
+ that causes the new object modal to appear (eg: clicking the
302
+ "New" button). Once the modal appears, the keywords for that
303
+ modal will be available for use in the test.
304
+
305
+ Example:
306
+
307
+ | Go to page Home Contact
308
+ | Click object button New
309
+ | Wait for modal to appear New Contact
310
+ """
311
+
312
+
313
+ @pageobject("Edit")
314
+ class EditModal(ModalMixin, BasePage):
315
+ """A page object representing the Edit Object modal
316
+
317
+ Note: You should not use this page object with 'Go to page'. Instead,
318
+ you can use 'Wait for modal to appear' after performing an action
319
+ that causes the new object modal to appear (eg: clicking the
320
+ "Edit" button). Once the modal appears, the keywords for that
321
+ modal will be available for use in the test.
322
+
323
+ Example:
324
+
325
+ | Click object button Edit
326
+ | Wait for modal to appear Edit Contact
327
+
328
+ """
329
+
330
+
331
+ @pageobject("Home")
332
+ class HomePage(BasePage):
333
+ """A page object representing the home page of an object.
334
+
335
+ When going to the Home page, you need to specify the object name.
336
+
337
+ Note: The home page of an object may automatically redirect you to
338
+ some other page, such as a Listing page. If you are working with
339
+ such a page, you might need to use `page should be` to load the
340
+ keywords for the page you expect to be redirected to.
341
+
342
+ Example
343
+
344
+ | Go to page Home Contact
345
+
346
+ """
347
+
348
+ def _go_to_page(self, locator=None):
349
+ url_template = "{root}/lightning/o/{object_name}/home"
350
+ url = url_template.format(
351
+ root=self.cumulusci.org.lightning_base_url, object_name=self.object_name
352
+ )
353
+ self.selenium.go_to(url)
354
+ self.salesforce.wait_until_loading_is_complete(locator=locator)
355
+
356
+ def _is_current_page(self):
357
+ self.selenium.location_should_contain(
358
+ "/lightning/o/{}/home".format(self.object_name)
359
+ )
360
+
361
+
362
+ @pageobject("Detail")
363
+ class DetailPage(BasePage):
364
+ """A page object representing the standard Detail page.
365
+
366
+ When going to this page via the standard `Go to page` keyword, you
367
+ can specify either an object id, or a set of keyword arguments which
368
+ will be used to look up the object id. When using keyword arguments,
369
+ they need to represent a unique user.
370
+
371
+ Example
372
+
373
+ | ${contact_id} = Salesforce Insert Contact
374
+ | ... FirstName=${first_name}
375
+ | ... LastName=${last_name}
376
+ |
377
+ | # Using the id:
378
+ | Go to page Detail Contact ${contact_id}
379
+ |
380
+ | # Using lookup parameters
381
+ | Go to page Detail Contact FirstName=${first_name} LastName=${last_name}
382
+
383
+ """
384
+
385
+ def _go_to_page(self, object_id=None, locator=None, **kwargs):
386
+ """Go to the detail page for the given record.
387
+
388
+ You may pass in an object id, or you may pass in keyword arguments
389
+ which can be used to look up the object.
390
+
391
+ Example
392
+
393
+ | Go to page Detail Contact firstName=John lastName=Smith
394
+ """
395
+
396
+ if kwargs and object_id:
397
+ raise Exception("Specify an object id or keyword arguments, but not both")
398
+
399
+ if kwargs:
400
+ # note: this will raise an exception if no object is found,
401
+ # or if multiple objects are found.
402
+ object_id = self._get_object(**kwargs)["Id"]
403
+
404
+ url_template = "{root}/lightning/r/{object_name}/{object_id}/view"
405
+ url = url_template.format(
406
+ root=self.cumulusci.org.lightning_base_url,
407
+ object_name=self.object_name,
408
+ object_id=object_id,
409
+ )
410
+ self.selenium.go_to(url)
411
+ self.salesforce.wait_until_loading_is_complete(locator=locator)
412
+
413
+ def _is_current_page(self, **kwargs):
414
+ """Verify we are on a detail page.
415
+
416
+ If keyword arguments are present, this function will go a query
417
+ on the given parameters, assert that the query returns a single
418
+ result, and the verify that the returned object id is part of the url.
419
+ """
420
+ if kwargs:
421
+ # do a lookup to get the object id
422
+ object_id = self._get_object(**kwargs)["Id"]
423
+ pattern = r"/lightning/r/{}/{}/view$".format(self.object_name, object_id)
424
+ else:
425
+ # no kwargs means we should just verify we are on a detail
426
+ # page without regard to which object
427
+ pattern = r"/lightning/r/{}/.*/view$".format(self.object_name)
428
+
429
+ location = self.selenium.get_location()
430
+ if not re.search(pattern, location):
431
+ raise Exception(
432
+ "Location '{}' didn't match pattern {}".format(location, pattern)
433
+ )
@@ -0,0 +1,246 @@
1
+ from selenium.webdriver.common.keys import Keys
2
+
3
+ from cumulusci.robotframework.pageobjects import BasePage, pageobject
4
+ from cumulusci.robotframework.utils import capture_screenshot_on_error
5
+
6
+ object_manager = {
7
+ "button": "//input[@title='{}']",
8
+ "input": "//input[@id='{}']",
9
+ "select_related": "//select[@id = '{}']",
10
+ "select_related_option": "//select[@id = 'DomainEnumOrId']/option[@value='{}']",
11
+ "search_result": "//section[@class='related-list-card']//a[.=\"{}\"]",
12
+ "formula_txtarea": "//textarea[@id = '{}']",
13
+ "object_result": "//th/a[text()='{}']",
14
+ "link-text": "//a[contains(text(),'{}')]",
15
+ "button-with-text": "//button[contains(text(),'{}')]",
16
+ "frame_new": "//iframe[contains(@name, '{}') or contains(@title, '{}')]",
17
+ "action_menu": "//tr[.//a[.='{}']]//div[contains(@class, 'objectManagerVirtualActionMenu')]//a",
18
+ "action_menu_item": "//div[@class='actionMenu']//a[@role='menuitem' and .='{}']",
19
+ "delete_confirm_btn": "//button[contains(@class,'forceActionButton')]",
20
+ }
21
+ # All common elements
22
+ search_button = object_manager["input"].format("globalQuickfind")
23
+ currency_locator = object_manager["input"].format("dtypeC")
24
+ next_button = object_manager["button"].format("Next")
25
+ save_button = object_manager["button"].format("Save")
26
+ text_locator = object_manager["input"].format("dtypeS")
27
+ formula_locator = object_manager["input"].format("dtypeZ")
28
+ checkbox_option = object_manager["input"].format("fdtypeB")
29
+ formula_txtarea = object_manager["formula_txtarea"].format("CalculatedFormula")
30
+ check_syntax = object_manager["button"].format("Check Syntax")
31
+ actions_menu = object_manager["action_menu"]
32
+ action_item_delete = object_manager["action_menu_item"].format("Delete")
33
+ confirm_delete = object_manager["delete_confirm_btn"]
34
+ lookup_locator = object_manager["input"].format("dtypeY")
35
+
36
+
37
+ @pageobject(page_type="ObjectManager")
38
+ class ObjectManagerPage(BasePage):
39
+ """A page object representing the Object Manager of an object.
40
+ Example
41
+ | Go to page ObjectManager Contact
42
+ """
43
+
44
+ def _go_to_page(self):
45
+ url_template = "{root}/lightning/setup/ObjectManager/home"
46
+ url = url_template.format(root=self.cumulusci.org.lightning_base_url)
47
+ self.selenium.go_to(url)
48
+ object_name = self.object_name
49
+ self.salesforce.wait_until_loading_is_complete()
50
+ self.selenium.wait_until_page_contains_element(search_button)
51
+ self.selenium.press_keys(search_button, object_name, "RETURN")
52
+ object_locator = object_manager["object_result"].format(object_name)
53
+ self.selenium.wait_until_element_is_visible(object_locator)
54
+ self.salesforce._jsclick(object_locator)
55
+ self.selenium.wait_until_location_contains("Details/view", timeout=90)
56
+
57
+ def _is_current_page(self):
58
+ self.selenium.location_should_contain("Details/view")
59
+
60
+ @capture_screenshot_on_error
61
+ def switch_tab_to(self, tab):
62
+ """Clicks on the name of the tab specified and sets the page view to be on the tab specified
63
+ Example
64
+ | Switch Tab To Fields & Relationships
65
+ """
66
+ leftnavoption = object_manager["link-text"].format(tab)
67
+ self.selenium.click_element(leftnavoption)
68
+
69
+ def _is_current_tab(self, tab):
70
+ tab_view = f"{tab}/view"
71
+ self.selenium.location_should_contain(tab_view)
72
+
73
+ @capture_screenshot_on_error
74
+ def create_currency_field(self, field_name):
75
+ """Creates a currency field by taking in the field name"""
76
+ self.selenium.wait_until_page_contains_element(currency_locator, timeout=60)
77
+ self.selenium.click_element(currency_locator)
78
+ self.selenium.wait_until_page_contains_element(next_button, 60)
79
+ self.selenium.click_element(next_button)
80
+ self.salesforce.populate_field("Field Label", field_name)
81
+ self.salesforce.populate_field("Length", "16")
82
+ self.salesforce.populate_field("Decimal Places", "2")
83
+ self.salesforce.populate_field(
84
+ "Description", "This is a custom field generated during automation"
85
+ )
86
+ self.selenium.click_element(next_button)
87
+ self.selenium.click_element(next_button)
88
+ self.selenium.click_element(save_button)
89
+ self.selenium.wait_until_location_contains(
90
+ "FieldsAndRelationships/view",
91
+ timeout=90,
92
+ message="Fields And Relationships page did not load in 1 min",
93
+ )
94
+
95
+ @capture_screenshot_on_error
96
+ def create_text_field(self, field_name):
97
+ """Creates a text field by taking in the field name"""
98
+ self.selenium.wait_until_page_contains_element(text_locator, timeout=60)
99
+ self.selenium.click_element(text_locator)
100
+ self.selenium.click_element(next_button)
101
+ self.salesforce.populate_field("Field Label", field_name)
102
+ self.salesforce.populate_field("Length", "255")
103
+ self.salesforce.populate_field(
104
+ "Description", "This is a custom field generated during automation"
105
+ )
106
+ self.selenium.click_element(next_button)
107
+ self.selenium.click_element(next_button)
108
+ self.selenium.click_element(save_button)
109
+ self.selenium.wait_until_location_contains(
110
+ "FieldsAndRelationships/view",
111
+ timeout=90,
112
+ message="Fields And Relationships page did not load in 1 min",
113
+ )
114
+
115
+ @capture_screenshot_on_error
116
+ def create_formula_field(self, field_name, formula):
117
+ """Creates a formula field by providing the field_name, formula and forumla fields"""
118
+ self.selenium.wait_until_page_contains_element(formula_locator, 60)
119
+ self.selenium.click_element(formula_locator)
120
+ self.selenium.wait_until_page_contains_element(next_button, 60)
121
+ self.selenium.click_element(next_button)
122
+ self.salesforce.populate_field("Field Label", field_name)
123
+ self.selenium.wait_until_page_contains_element(checkbox_option, 60)
124
+ self.selenium.click_element(checkbox_option)
125
+ self.selenium.click_element(next_button)
126
+ self.selenium.wait_until_page_contains_element(formula_txtarea, 60)
127
+ self.selenium.get_webelement(formula_txtarea).send_keys(formula)
128
+ self.selenium.click_element(check_syntax)
129
+ self.selenium.click_element(next_button)
130
+ self.selenium.click_element(next_button)
131
+ self.selenium.click_element(save_button)
132
+ self.selenium.wait_until_location_contains(
133
+ "FieldsAndRelationships/view",
134
+ timeout=90,
135
+ message="Detail page did not load in 1 min",
136
+ )
137
+
138
+ def create_lookup_field(self, field_name, related):
139
+ """Creates a Lookup field by taking in the inputs field_name and related field"""
140
+ option = object_manager["select_related_option"].format(related)
141
+ related = object_manager["select_related"].format("DomainEnumOrId")
142
+ self.selenium.wait_until_page_contains_element(lookup_locator, 60)
143
+ self.selenium.click_element(lookup_locator)
144
+ self.selenium.wait_until_page_contains_element(next_button, 60)
145
+ self.selenium.click_element(next_button)
146
+ self.selenium.wait_until_page_contains_element(related, 60)
147
+ self.salesforce.scroll_element_into_view(related)
148
+ self.selenium.get_webelement(related).click()
149
+ self.selenium.click_element(option)
150
+ self.selenium.wait_until_page_contains_element(next_button, 60)
151
+ self.selenium.click_element(next_button)
152
+ self.salesforce.populate_field("Field Label", field_name)
153
+ self.salesforce.populate_field(
154
+ "Description", "This is a custom field generated during automation"
155
+ )
156
+ self.selenium.click_element(next_button)
157
+ self.selenium.click_element(next_button)
158
+ self.selenium.click_element(next_button)
159
+ self.selenium.click_element(save_button)
160
+ self.selenium.wait_until_location_contains(
161
+ "FieldsAndRelationships/view",
162
+ timeout=90,
163
+ message="Detail page did not load in 1 min",
164
+ )
165
+
166
+ @capture_screenshot_on_error
167
+ def is_field_present(self, field_name):
168
+ """Searches for the field name (field_name) and asserts the field got created"""
169
+ self.selenium.wait_until_page_contains_element(search_button)
170
+ self.selenium.clear_element_text(search_button)
171
+ self.selenium.press_keys(search_button, field_name, "ENTER")
172
+ self.selenium.wait_until_element_is_not_visible("sf:spinner")
173
+ search_results = object_manager["search_result"].format(field_name)
174
+ self.selenium.wait_until_page_contains_element(search_results)
175
+
176
+ @capture_screenshot_on_error
177
+ def delete_custom_field(self, field_name):
178
+ """Searches for the custom field and performs the delete action from the actions menu next to the field"""
179
+ action_menu_button = actions_menu.format(field_name)
180
+ self.is_field_present(field_name)
181
+
182
+ self.selenium.wait_until_page_contains_element(action_menu_button)
183
+ self.salesforce.scroll_element_into_view(action_menu_button)
184
+
185
+ # I don't know why, but sometimes clicking the action menu just
186
+ # doesn't work. The menu doesn't appear, or clicking the item on
187
+ # the menu does nothing. So, we'll try and handful of times.
188
+ # Yes, this feels icky.
189
+ for tries in range(5):
190
+ try:
191
+ self.selenium.wait_until_element_is_visible(action_menu_button)
192
+ self.selenium.click_element(action_menu_button)
193
+ self.selenium.wait_until_element_is_visible(
194
+ action_item_delete, timeout="5 seconds"
195
+ )
196
+ self.selenium.click_element(action_item_delete, action_chain=True)
197
+ self.selenium.wait_until_element_is_visible(
198
+ confirm_delete, timeout="5 seconds"
199
+ )
200
+ self.selenium.click_element(confirm_delete, action_chain=True)
201
+ self.selenium.wait_until_location_contains("/view", timeout=90)
202
+ return
203
+
204
+ except Exception as e:
205
+ self.builtin.log(
206
+ f"on try #{tries+1} we caught this error: {e}", "DEBUG"
207
+ )
208
+ self.builtin.sleep("1 second")
209
+ last_error = e
210
+ raise (last_error)
211
+
212
+ @capture_screenshot_on_error
213
+ def create_custom_field(self, **kwargs):
214
+ """creates a custom field if one doesn't already exist by the given name (Field_Name)
215
+ | Example
216
+ | Create custom field
217
+ | ... Object=Payment
218
+ | ... Field_Type=Formula
219
+ | ... Field_Name=Is Opportunity From Prior Year
220
+ | ... Formula=YEAR( npe01__Opportunity__r.CloseDate ) < YEAR( npe01__Payment_Date__c )
221
+ """
222
+ self.selenium.wait_until_page_contains_element(search_button, 60)
223
+ self.selenium.get_webelement(search_button).send_keys(kwargs["Field_Name"])
224
+ self.selenium.get_webelement(search_button).send_keys(Keys.ENTER)
225
+ self.salesforce.wait_until_loading_is_complete()
226
+ search_results = object_manager["search_result"].format(kwargs["Field_Name"])
227
+ count = len(self.selenium.get_webelements(search_results))
228
+ if count != 1:
229
+ locator = object_manager["button-with-text"].format("New")
230
+ self.selenium.wait_until_page_contains_element(locator, 60)
231
+ self.selenium.get_webelement(locator).click()
232
+ self.salesforce.wait_until_loading_is_complete()
233
+ framelocator = object_manager["frame_new"].format("vfFrameId", "vfFrameId")
234
+ self.selenium.wait_until_element_is_visible(framelocator, timeout=60)
235
+ frame = self.selenium.get_webelement(framelocator)
236
+ self.selenium.select_frame(frame)
237
+ type = kwargs["Field_Type"]
238
+ if type.lower() == "lookup":
239
+ self.create_lookup_field(kwargs["Field_Name"], kwargs["Related_To"])
240
+ elif type.lower() == "currency":
241
+ self.create_currency_field(kwargs["Field_Name"])
242
+ elif type.lower() == "formula":
243
+ self.create_formula_field(kwargs["Field_Name"], kwargs["Formula"])
244
+ elif type.lower() == "text":
245
+ self.create_text_field(kwargs["Field_Name"])
246
+ self.selenium.unselect_frame()