@rockcarver/frodo-cli 0.13.2 → 0.14.0

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.
Files changed (138) hide show
  1. package/CHANGELOG.md +34 -1
  2. package/babel.config.esm.json +6 -0
  3. package/package.json +14 -7
  4. package/src/{app.js → app.ts} +14 -14
  5. package/src/cli/_template/{cmd-delete.js → cmd-delete.ts} +0 -0
  6. package/src/cli/_template/{cmd-describe.js → cmd-describe.ts} +0 -0
  7. package/src/cli/_template/{cmd-export.js → cmd-export.ts} +0 -0
  8. package/src/cli/_template/{cmd-import.js → cmd-import.ts} +0 -0
  9. package/src/cli/_template/{cmd-list.js → cmd-list.ts} +0 -0
  10. package/src/cli/_template/{cmd-sub1-delete.js → cmd-sub1-delete.ts} +0 -0
  11. package/src/cli/_template/{cmd-sub1-describe.js → cmd-sub1-describe.ts} +0 -0
  12. package/src/cli/_template/{cmd-sub1-export.js → cmd-sub1-export.ts} +0 -0
  13. package/src/cli/_template/{cmd-sub1-import.js → cmd-sub1-import.ts} +0 -0
  14. package/src/cli/_template/{cmd-sub1-list.js → cmd-sub1-list.ts} +0 -0
  15. package/src/cli/_template/{cmd-sub1.js → cmd-sub1.ts} +0 -0
  16. package/src/cli/_template/{cmd-sub2-delete.js → cmd-sub2-delete.ts} +0 -0
  17. package/src/cli/_template/{cmd-sub2-describe.js → cmd-sub2-describe.ts} +0 -0
  18. package/src/cli/_template/{cmd-sub2-export.js → cmd-sub2-export.ts} +0 -0
  19. package/src/cli/_template/{cmd-sub2-import.js → cmd-sub2-import.ts} +0 -0
  20. package/src/cli/_template/{cmd-sub2-list.js → cmd-sub2-list.ts} +0 -0
  21. package/src/cli/_template/{cmd-sub2.js → cmd-sub2.ts} +0 -0
  22. package/src/cli/_template/{cmd.js → cmd.ts} +0 -0
  23. package/src/cli/admin/{admin-add-autoid-static-user-mapping.js → admin-add-autoid-static-user-mapping.ts} +0 -0
  24. package/src/cli/admin/{admin-create-oauth2-client-with-admin-privileges.js → admin-create-oauth2-client-with-admin-privileges.ts} +0 -0
  25. package/src/cli/admin/{admin-get-access-token.js → admin-get-access-token.ts} +0 -0
  26. package/src/cli/admin/{admin-grant-oauth2-client-admin-privileges.js → admin-grant-oauth2-client-admin-privileges.ts} +0 -0
  27. package/src/cli/admin/{admin-hide-generic-extension-attributes.js → admin-hide-generic-extension-attributes.ts} +0 -0
  28. package/src/cli/admin/{admin-list-oauth2-clients-with-admin-privileges.js → admin-list-oauth2-clients-with-admin-privileges.ts} +0 -0
  29. package/src/cli/admin/{admin-list-oauth2-clients-with-custom-privileges.js → admin-list-oauth2-clients-with-custom-privileges.ts} +0 -0
  30. package/src/cli/admin/{admin-list-static-user-mappings.js → admin-list-static-user-mappings.ts} +0 -0
  31. package/src/cli/admin/{admin-remove-static-user-mapping.js → admin-remove-static-user-mapping.ts} +0 -0
  32. package/src/cli/admin/{admin-repair-org-model.js → admin-repair-org-model.ts} +7 -1
  33. package/src/cli/admin/{admin-revoke-oauth2-client-admin-privileges.js → admin-revoke-oauth2-client-admin-privileges.ts} +0 -0
  34. package/src/cli/admin/{admin-show-generic-extension-attributes.js → admin-show-generic-extension-attributes.ts} +0 -0
  35. package/src/cli/admin/{admin.js → admin.ts} +0 -0
  36. package/src/cli/app/{app-delete.js → app-delete.ts} +0 -0
  37. package/src/cli/app/{app-describe.js → app-describe.ts} +0 -0
  38. package/src/cli/app/{app-export.js → app-export.ts} +0 -0
  39. package/src/cli/app/{app-import.js → app-import.ts} +0 -0
  40. package/src/cli/app/{app-list.js → app-list.ts} +0 -0
  41. package/src/cli/app/{app.js → app.ts} +0 -0
  42. package/src/cli/{cmd_common.js → cmd_common.ts} +0 -0
  43. package/src/cli/conn/{conn-add.js → conn-add.ts} +0 -0
  44. package/src/cli/conn/{conn-delete.js → conn-delete.ts} +0 -0
  45. package/src/cli/conn/{conn-describe.js → conn-describe.ts} +0 -0
  46. package/src/cli/conn/{conn-list.js → conn-list.ts} +0 -0
  47. package/src/cli/conn/{conn.js → conn.ts} +0 -0
  48. package/src/cli/email/{email-template-export.js → email-template-export.ts} +0 -0
  49. package/src/cli/email/{email-template-import.js → email-template-import.ts} +0 -0
  50. package/src/cli/email/{email-template-list.js → email-template-list.ts} +0 -0
  51. package/src/cli/email/{email-template.js → email-template.ts} +0 -0
  52. package/src/cli/email/{email.js → email.ts} +0 -0
  53. package/src/cli/esv/{esv-apply.js → esv-apply.ts} +0 -0
  54. package/src/cli/esv/{esv-secret-create.js → esv-secret-create.ts} +0 -0
  55. package/src/cli/esv/{esv-secret-delete.js → esv-secret-delete.ts} +0 -0
  56. package/src/cli/esv/{esv-secret-describe.js → esv-secret-describe.ts} +0 -0
  57. package/src/cli/esv/{esv-secret-export.js → esv-secret-export.ts} +0 -0
  58. package/src/cli/esv/{esv-secret-import.js → esv-secret-import.ts} +0 -0
  59. package/src/cli/esv/{esv-secret-list.js → esv-secret-list.ts} +0 -0
  60. package/src/cli/esv/{esv-secret-set.js → esv-secret-set.ts} +0 -0
  61. package/src/cli/esv/{esv-secret-version-activate.js → esv-secret-version-activate.ts} +0 -0
  62. package/src/cli/esv/{esv-secret-version-create.js → esv-secret-version-create.ts} +0 -0
  63. package/src/cli/esv/{esv-secret-version-deactivate.js → esv-secret-version-deactivate.ts} +0 -0
  64. package/src/cli/esv/{esv-secret-version-delete.js → esv-secret-version-delete.ts} +0 -0
  65. package/src/cli/esv/{esv-secret-version-list.js → esv-secret-version-list.ts} +0 -0
  66. package/src/cli/esv/{esv-secret-version.js → esv-secret-version.ts} +0 -0
  67. package/src/cli/esv/{esv-secret.js → esv-secret.ts} +0 -0
  68. package/src/cli/esv/{esv-variable-create.js → esv-variable-create.ts} +0 -0
  69. package/src/cli/esv/{esv-variable-delete.js → esv-variable-delete.ts} +0 -0
  70. package/src/cli/esv/{esv-variable-describe.js → esv-variable-describe.ts} +0 -0
  71. package/src/cli/esv/{esv-variable-export.js → esv-variable-export.ts} +0 -0
  72. package/src/cli/esv/{esv-variable-import.js → esv-variable-import.ts} +0 -0
  73. package/src/cli/esv/{esv-variable-list.js → esv-variable-list.ts} +0 -0
  74. package/src/cli/esv/{esv-variable-set.js → esv-variable-set.ts} +0 -0
  75. package/src/cli/esv/{esv-variable.js → esv-variable.ts} +0 -0
  76. package/src/cli/esv/{esv.js → esv.ts} +0 -0
  77. package/src/cli/idm/{idm-count.js → idm-count.ts} +0 -0
  78. package/src/cli/idm/{idm-export.js → idm-export.ts} +0 -0
  79. package/src/cli/idm/{idm-list.js → idm-list.ts} +0 -0
  80. package/src/cli/idm/{idm.js → idm.ts} +0 -0
  81. package/src/cli/idp/{idp-export.js → idp-export.ts} +0 -0
  82. package/src/cli/idp/{idp-import.js → idp-import.ts} +0 -0
  83. package/src/cli/idp/{idp-list.js → idp-list.ts} +0 -0
  84. package/src/cli/idp/{idp.js → idp.ts} +0 -0
  85. package/src/cli/info/{info.js → info.ts} +1 -1
  86. package/src/cli/journey/journey-delete.e2e.test_.ts +380 -0
  87. package/src/cli/journey/{journey-delete.js → journey-delete.ts} +0 -0
  88. package/src/cli/journey/{journey-describe.js → journey-describe.ts} +60 -12
  89. package/src/cli/journey/{journey-export.js → journey-export.ts} +0 -0
  90. package/src/cli/journey/{journey-import.js → journey-import.ts} +0 -0
  91. package/src/cli/journey/journey-list.e2e.test_.ts +142 -0
  92. package/src/cli/journey/{journey-list.js → journey-list.ts} +0 -0
  93. package/src/cli/journey/{journey-prune.js → journey-prune.ts} +0 -0
  94. package/src/cli/journey/{journey.js → journey.ts} +0 -0
  95. package/src/cli/logging/{logs-list.js → logs-list.ts} +0 -0
  96. package/src/cli/logging/{logs-tail.js → logs-tail.ts} +0 -0
  97. package/src/cli/logging/{logs.js → logs.ts} +0 -0
  98. package/src/cli/realm/{realm-add-custom-domain.js → realm-add-custom-domain.ts} +0 -0
  99. package/src/cli/realm/{realm-describe.js → realm-describe.ts} +0 -0
  100. package/src/cli/realm/{realm-list.js → realm-list.ts} +0 -0
  101. package/src/cli/realm/{realm-remove-custom-domain.js → realm-remove-custom-domain.ts} +0 -0
  102. package/src/cli/realm/{realm.js → realm.ts} +0 -0
  103. package/src/cli/saml/{saml-cot-export.js → saml-cot-export.ts} +0 -0
  104. package/src/cli/saml/{saml-cot-import.js → saml-cot-import.ts} +0 -0
  105. package/src/cli/saml/{saml-cot-list.js → saml-cot-list.ts} +0 -0
  106. package/src/cli/saml/{saml-cot.js → saml-cot.ts} +0 -0
  107. package/src/cli/saml/{saml-describe.js → saml-describe.ts} +0 -0
  108. package/src/cli/saml/{saml-export.js → saml-export.ts} +0 -0
  109. package/src/cli/saml/{saml-import.js → saml-import.ts} +0 -0
  110. package/src/cli/saml/{saml-list.js → saml-list.ts} +0 -0
  111. package/src/cli/saml/{saml-metadata-export.js → saml-metadata-export.ts} +0 -0
  112. package/src/cli/saml/{saml-metadata.js → saml-metadata.ts} +0 -0
  113. package/src/cli/saml/{saml.js → saml.ts} +0 -0
  114. package/src/cli/script/{script-delete.js → script-delete.ts} +0 -0
  115. package/src/cli/script/{script-describe.js → script-describe.ts} +0 -0
  116. package/src/cli/script/{script-export.js → script-export.ts} +0 -0
  117. package/src/cli/script/{script-import.js → script-import.ts} +0 -0
  118. package/src/cli/script/{script-list.js → script-list.ts} +0 -0
  119. package/src/cli/script/{script.js → script.ts} +0 -0
  120. package/src/cli/theme/theme-delete.e2e.test_.ts +178 -0
  121. package/src/cli/theme/{theme-delete.js → theme-delete.ts} +0 -0
  122. package/src/cli/theme/{theme-export.js → theme-export.ts} +0 -0
  123. package/src/cli/theme/{theme-import.js → theme-import.ts} +0 -0
  124. package/src/cli/theme/theme-list.e2e.test_.ts +119 -0
  125. package/src/cli/theme/{theme-list.js → theme-list.ts} +0 -0
  126. package/src/cli/theme/{theme.js → theme.ts} +0 -0
  127. package/src/ops/CirclesOfTrustOps.ts +12 -0
  128. package/src/ops/EmailTemplateOps.ts +19 -0
  129. package/src/ops/IdpOps.ts +11 -0
  130. package/src/ops/JourneyOps.ts +278 -0
  131. package/src/ops/NodeOps.ts +47 -0
  132. package/src/ops/Saml2Ops.ts +24 -0
  133. package/src/ops/ScriptOps.ts +11 -0
  134. package/src/ops/ThemeOps.ts +17 -0
  135. package/src/ops/utils/Wordwrap.ts +11 -0
  136. package/src/storage/{StaticStorage.js → StaticStorage.ts} +0 -0
  137. package/src/utils/{Console.js → Console.ts} +3 -2
  138. package/tsconfig.json +6 -6
@@ -0,0 +1,380 @@
1
+ // import { jest } from '@jest/globals';
2
+ import { spawn, spawnSync } from 'child_process';
3
+
4
+ const ansiEscapeCodes =
5
+ // eslint-disable-next-line no-control-regex
6
+ /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
7
+
8
+ /**
9
+ * Run once before running the suites in this file
10
+ */
11
+ beforeAll(async () => {});
12
+
13
+ /**
14
+ * Run before every test in every suite in this file
15
+ */
16
+ beforeEach(async () => {
17
+ // delete all journeys
18
+ const deleteJourneysCmd = spawnSync('frodo', [
19
+ 'journey',
20
+ 'delete',
21
+ '--all',
22
+ 'frodo-dev',
23
+ ]);
24
+ if (deleteJourneysCmd.status > 0) {
25
+ console.error(deleteJourneysCmd.stderr.toString());
26
+ console.log(deleteJourneysCmd.stdout.toString());
27
+ }
28
+
29
+ // import test journeys
30
+ const importTestJourneysCmd = spawnSync(
31
+ 'frodo',
32
+ ['journey', 'import', '--all-separate', 'frodo-dev'],
33
+ {
34
+ cwd: `test/e2e/journey/delete`,
35
+ }
36
+ );
37
+ if (importTestJourneysCmd.status > 0) {
38
+ console.error(importTestJourneysCmd.stderr.toString());
39
+ console.log(importTestJourneysCmd.stdout.toString());
40
+ }
41
+ });
42
+
43
+ describe('frodo journey delete', () => {
44
+ it('"frodo journey delete -i deleteMe": should delete the deleteMe journey and all its nodes', (done) => {
45
+ const deleteJourneyCmd = spawn('frodo', [
46
+ 'journey',
47
+ 'delete',
48
+ '-i',
49
+ 'deleteMe',
50
+ 'frodo-dev',
51
+ ]);
52
+ const expected = ['✔ Deleted deleteMe and 7/7 nodes.', ''].join('\n');
53
+ const chunks = [];
54
+ deleteJourneyCmd.stderr.on('data', (chunk) => {
55
+ chunks.push(chunk);
56
+ });
57
+ deleteJourneyCmd.stderr.on('end', () => {
58
+ const output = Buffer.concat(chunks)
59
+ .toString()
60
+ .replace(ansiEscapeCodes, '');
61
+ try {
62
+ expect(output).toContain(expected);
63
+ done();
64
+ } catch (error) {
65
+ done(error);
66
+ }
67
+ });
68
+ });
69
+
70
+ it('"frodo journey delete -i deleteMe --verbose": should delete the deleteMe journey and all its nodes with verbose output', (done) => {
71
+ const deleteJourneyCmd = spawn('frodo', [
72
+ 'journey',
73
+ 'delete',
74
+ '-i',
75
+ 'deleteMe',
76
+ '--verbose',
77
+ 'frodo-dev',
78
+ ]);
79
+ const expected = [
80
+ 'Deleted deleteMe (tree)\n',
81
+ 'Read 3c89697f-c114-4d36-907f-6c36f820cde7 (PageNode) from deleteMe\n',
82
+ 'Deleted 68e23c54-0c9e-4991-9b25-daf306d6ec65 (ZeroPageLoginNode) from deleteMe\n',
83
+ 'Deleted 9cd184fc-9453-4666-b667-2875d9301b5e (DataStoreDecisionNode) from deleteMe\n',
84
+ 'Read 2d564be0-325e-439a-aeb0-6c884270c756 (PageNode) from deleteMe\n',
85
+ 'Deleted 3c89697f-c114-4d36-907f-6c36f820cde7 (PageNode) from deleteMe\n',
86
+ 'Deleted fab1f53e-cda4-458a-b458-b07f75c75d5f (ValidatedUsernameNode) from deleteMe\n',
87
+ 'Deleted 2d564be0-325e-439a-aeb0-6c884270c756 (PageNode) from deleteMe\n',
88
+ 'Deleted 9d146833-e8d1-4802-8c35-0d7772290807 (DisplayUserNameNode) from deleteMe\n',
89
+ 'Deleted c22373f9-252b-4d0b-b80e-e4b392a17d98 (ValidatedPasswordNode) from deleteMe\n',
90
+ '✔ Deleted deleteMe and 7/7 nodes.\n',
91
+ ];
92
+ const chunks = [];
93
+ deleteJourneyCmd.stderr.on('data', (chunk) => {
94
+ chunks.push(chunk);
95
+ });
96
+ deleteJourneyCmd.stderr.on('end', () => {
97
+ const output = Buffer.concat(chunks)
98
+ .toString()
99
+ .replace(ansiEscapeCodes, '');
100
+ try {
101
+ for (const str of expected) {
102
+ expect(output).toContain(str);
103
+ }
104
+ done();
105
+ } catch (error) {
106
+ done(error);
107
+ }
108
+ });
109
+ });
110
+
111
+ it('"frodo journey delete -i deleteMe --no-deep": should delete the deleteMe journey and none of its nodes', (done) => {
112
+ const deleteJourneyCmd = spawn('frodo', [
113
+ 'journey',
114
+ 'delete',
115
+ '-i',
116
+ 'deleteMe',
117
+ '--no-deep',
118
+ 'frodo-dev',
119
+ ]);
120
+ const expected = ['✔ Deleted deleteMe and 0/0 nodes.', ''].join('\n');
121
+ const chunks = [];
122
+ deleteJourneyCmd.stderr.on('data', (chunk) => {
123
+ chunks.push(chunk);
124
+ });
125
+ deleteJourneyCmd.stderr.on('end', () => {
126
+ const output = Buffer.concat(chunks)
127
+ .toString()
128
+ .replace(ansiEscapeCodes, '');
129
+ try {
130
+ expect(output).toContain(expected);
131
+ done();
132
+ } catch (error) {
133
+ done(error);
134
+ }
135
+ });
136
+ });
137
+
138
+ it('"frodo journey delete -i deleteMe --no-deep --verbose": should delete the deleteMe journey and none of its nodes with verbose output', (done) => {
139
+ const deleteJourneyCmd = spawn('frodo', [
140
+ 'journey',
141
+ 'delete',
142
+ '-i',
143
+ 'deleteMe',
144
+ '--no-deep',
145
+ '--verbose',
146
+ 'frodo-dev',
147
+ ]);
148
+ const expected = [
149
+ 'Deleted deleteMe (tree)\n',
150
+ '✔ Deleted deleteMe and 0/0 nodes.\n',
151
+ ];
152
+ const chunks = [];
153
+ deleteJourneyCmd.stderr.on('data', (chunk) => {
154
+ chunks.push(chunk);
155
+ });
156
+ deleteJourneyCmd.stderr.on('end', () => {
157
+ const output = Buffer.concat(chunks)
158
+ .toString()
159
+ .replace(ansiEscapeCodes, '');
160
+ try {
161
+ for (const str of expected) {
162
+ expect(output).toContain(str);
163
+ }
164
+ done();
165
+ } catch (error) {
166
+ done(error);
167
+ }
168
+ });
169
+ });
170
+ });
171
+
172
+ describe('frodo journey delete --all', () => {
173
+ it(
174
+ '"frodo journey delete -a": should delete all journeys and all their nodes',
175
+ (done) => {
176
+ const deleteJourneyCmd = spawn('frodo', [
177
+ 'journey',
178
+ 'delete',
179
+ '-a',
180
+ 'frodo-dev',
181
+ ]);
182
+ const expected = [
183
+ '[========================================] 100% | 8/8 | Deleted 8/8 journeys and 51/51 nodes.',
184
+ '',
185
+ ].join('\n');
186
+ const chunks = [];
187
+ deleteJourneyCmd.stderr.on('data', (chunk) => {
188
+ chunks.push(chunk);
189
+ });
190
+ deleteJourneyCmd.stderr.on('end', () => {
191
+ const output = Buffer.concat(chunks)
192
+ .toString()
193
+ .replace(ansiEscapeCodes, '');
194
+ try {
195
+ expect(output).toContain(expected);
196
+ done();
197
+ } catch (error) {
198
+ done(error);
199
+ }
200
+ });
201
+ },
202
+ // increase timeout for long-running test
203
+ 10 * 1000
204
+ );
205
+
206
+ it(
207
+ '"frodo journey delete -a --verbose": should delete all journeys and all their nodes with verbose output',
208
+ (done) => {
209
+ const deleteJourneyCmd = spawn('frodo', [
210
+ 'journey',
211
+ 'delete',
212
+ '-a',
213
+ '--verbose',
214
+ 'frodo-dev',
215
+ ]);
216
+ const expected = [
217
+ '[----------------------------------------] 0% | 0/8 | Deleting journeys...\n',
218
+ 'Deleted ResetPassword (tree)\n',
219
+ 'Read cc3e1ed2-25f1-47bf-83c6-17084f8b2b2b (PageNode) from ResetPassword\n',
220
+ 'Deleted 06c97be5-7fdd-4739-aea1-ecc7fe082865 (EmailSuspendNode) from ResetPassword\n',
221
+ 'Deleted 989f0bf8-a328-4217-b82b-5275d79ca8bd (PatchObjectNode) from ResetPassword\n',
222
+ 'Deleted 21b8ddf3-0203-4ae1-ab05-51cf3a3a707a (IdentifyExistingUserNode) from ResetPassword\n',
223
+ 'Read e4c752f9-c625-48c9-9644-a58802fa9e9c (PageNode) from ResetPassword\n',
224
+ 'Deleted cc3e1ed2-25f1-47bf-83c6-17084f8b2b2b (PageNode) from ResetPassword\n',
225
+ 'Deleted 276afa7c-a680-4cf4-a5f6-d6c78191f5c9 (AttributeCollectorNode) from ResetPassword\n',
226
+ 'Deleted e4c752f9-c625-48c9-9644-a58802fa9e9c (PageNode) from ResetPassword\n',
227
+ 'Deleted 009c19c8-9572-47bb-adb2-1f092c559a43 (ValidatedPasswordNode) from ResetPassword\n',
228
+ 'Deleted Registration (tree)\n',
229
+ 'Read 0c091c49-f3af-48fb-ac6f-07fba0499dd6 (PageNode) from Registration\n',
230
+ 'Deleted d3ce2036-1523-4ce8-b1a2-895a2a036667 (AttributeCollectorNode) from Registration\n',
231
+ 'Deleted 0c091c49-f3af-48fb-ac6f-07fba0499dd6 (PageNode) from Registration\n',
232
+ 'Deleted 3d8709a1-f09f-4d1f-8094-2850e472c1db (ValidatedPasswordNode) from Registration\n',
233
+ 'Deleted 120c69d3-90b4-4ad4-b7af-380e8b119340 (KbaCreateNode) from Registration\n',
234
+ 'Deleted b4a0e915-c15d-4b83-9c9d-18347d645976 (AcceptTermsAndConditionsNode) from Registration\n',
235
+ 'Deleted ad5dcbb3-7335-49b7-b3e7-7d850bb88237 (CreateObjectNode) from Registration\n',
236
+ 'Deleted 7fcaf48e-a754-4959-858b-05b2933b825f (ValidatedUsernameNode) from Registration\n',
237
+ 'Deleted 97a15eb2-a015-4b6d-81a0-be78c3aa1a3b (IncrementLoginCountNode) from Registration\n',
238
+ 'Deleted PasswordGrant (tree)\n',
239
+ 'Read 6b9a715d-ea23-4eae-9a59-69797c147157 (PageNode) from PasswordGrant\n',
240
+ 'Deleted 59952413-9bc2-47e5-a9b2-b04c1d729e24 (UsernameCollectorNode) from PasswordGrant\n',
241
+ 'Deleted 6b9a715d-ea23-4eae-9a59-69797c147157 (PageNode) from PasswordGrant\n',
242
+ 'Deleted 8c217417-11dd-4a0f-a9e4-59c2390085be (PasswordCollectorNode) from PasswordGrant\n',
243
+ 'Deleted e2988546-a459-4c9a-b0e2-fa65ae136b34 (DataStoreDecisionNode) from PasswordGrant\n',
244
+ 'Deleted ProgressiveProfile (tree)\n',
245
+ 'Read a5aecad8-854a-4ed5-b719-ff6c90e858c0 (PageNode) from ProgressiveProfile\n',
246
+ 'Deleted 423a959a-a1b9-498a-b0f7-596b6b6e775a (PatchObjectNode) from ProgressiveProfile\n',
247
+ 'Deleted a1f45b44-5bf7-4c57-aa3f-75c619c7db8e (QueryFilterDecisionNode) from ProgressiveProfile\n',
248
+ 'Deleted 8afdaec3-275e-4301-bb53-34f03e6a4b29 (LoginCountDecisionNode) from ProgressiveProfile\n',
249
+ 'Deleted a5aecad8-854a-4ed5-b719-ff6c90e858c0 (PageNode) from ProgressiveProfile\n',
250
+ 'Deleted 0a042e10-b22e-4e02-86c4-65e26e775f7a (AttributeCollectorNode) from ProgressiveProfile\n',
251
+ 'Deleted ForgottenUsername (tree)\n',
252
+ 'Read 5e2a7c95-94af-4b23-8724-deb13853726a (PageNode) from ForgottenUsername\n',
253
+ 'Deleted 5e2a7c95-94af-4b23-8724-deb13853726a (PageNode) from ForgottenUsername\n',
254
+ 'Deleted 9f1e8d94-4922-481b-9e14-212b66548900 (AttributeCollectorNode) from ForgottenUsername\n',
255
+ 'Deleted bf9ea8d5-9802-4f26-9664-a21840faac23 (IdentifyExistingUserNode) from ForgottenUsername\n',
256
+ 'Deleted d9a79f01-2ce3-4be2-a28a-975f35c3c8ca (EmailSuspendNode) from ForgottenUsername\n',
257
+ 'Deleted b93ce36e-1976-4610-b24f-8d6760b5463b (InnerTreeEvaluatorNode) from ForgottenUsername\n',
258
+ 'Deleted deleteMe (tree)\n',
259
+ 'Read 3c89697f-c114-4d36-907f-6c36f820cde7 (PageNode) from deleteMe\n',
260
+ 'Deleted 9cd184fc-9453-4666-b667-2875d9301b5e (DataStoreDecisionNode) from deleteMe\n',
261
+ 'Read 2d564be0-325e-439a-aeb0-6c884270c756 (PageNode) from deleteMe\n',
262
+ 'Deleted 68e23c54-0c9e-4991-9b25-daf306d6ec65 (ZeroPageLoginNode) from deleteMe\n',
263
+ 'Deleted 3c89697f-c114-4d36-907f-6c36f820cde7 (PageNode) from deleteMe\n',
264
+ 'Deleted fab1f53e-cda4-458a-b458-b07f75c75d5f (ValidatedUsernameNode) from deleteMe\n',
265
+ 'Deleted c22373f9-252b-4d0b-b80e-e4b392a17d98 (ValidatedPasswordNode) from deleteMe\n',
266
+ 'Deleted 2d564be0-325e-439a-aeb0-6c884270c756 (PageNode) from deleteMe\n',
267
+ 'Deleted 9d146833-e8d1-4802-8c35-0d7772290807 (DisplayUserNameNode) from deleteMe\n',
268
+ 'Deleted UpdatePassword (tree)\n',
269
+ 'Read 20237b34-26cb-4a0b-958f-abb422290d42 (PageNode) from UpdatePassword\n',
270
+ 'Read d018fcd1-4e22-4160-8c41-63bee51c9cb3 (PageNode) from UpdatePassword\n',
271
+ 'Deleted 0f0904e6-1da3-4cdb-9abf-0d2545016fab (AttributePresentDecisionNode) from UpdatePassword\n',
272
+ 'Deleted 20237b34-26cb-4a0b-958f-abb422290d42 (PageNode) from UpdatePassword\n',
273
+ 'Deleted 7d1deabe-cd98-49c8-943f-ca12305775f3 (DataStoreDecisionNode) from UpdatePassword\n',
274
+ 'Deleted fe2962fc-4db3-4066-8624-553649afc438 (ValidatedPasswordNode) from UpdatePassword\n',
275
+ 'Deleted 3990ce1f-cce6-435b-ae1c-f138e89411c1 (PatchObjectNode) from UpdatePassword\n',
276
+ 'Deleted a3d97b53-e38a-4b24-aed0-a021050eb744 (EmailSuspendNode) from UpdatePassword\n',
277
+ 'Deleted d018fcd1-4e22-4160-8c41-63bee51c9cb3 (PageNode) from UpdatePassword\n',
278
+ 'Deleted 21a99653-a7a7-47ee-b650-f493a84bba09 (ValidatedPasswordNode) from UpdatePassword\n',
279
+ 'Deleted d1b79744-493a-44fe-bc26-7d324a8caa4e (SessionDataNode) from UpdatePassword\n',
280
+ 'Deleted Login (tree)\n',
281
+ 'Read a12bc72f-ad97-4f1e-a789-a1fa3dd566c8 (PageNode) from Login\n',
282
+ 'Deleted 33b24514-3e50-4180-8f08-ab6f4e51b07e (InnerTreeEvaluatorNode) from Login\n',
283
+ 'Deleted 2998c1c9-f4c8-4a00-b2c6-3426783ee49d (DataStoreDecisionNode) from Login\n',
284
+ 'Deleted 7354982f-57b6-4b04-9ddc-f1dd1e1e07d0 (ValidatedUsernameNode) from Login\n',
285
+ 'Deleted bba3e0d8-8525-4e82-bf48-ac17f7988917 (IncrementLoginCountNode) from Login\n',
286
+ 'Deleted 0c80c39b-4813-4e67-b4fb-5a0bba85f994 (ValidatedPasswordNode) from Login\n',
287
+ 'Deleted a12bc72f-ad97-4f1e-a789-a1fa3dd566c8 (PageNode) from Login\n',
288
+ '[========================================] 100% | 8/8 | Deleted 8/8 journeys and 51/51 nodes.\n',
289
+ ];
290
+ const chunks = [];
291
+ deleteJourneyCmd.stderr.on('data', (chunk) => {
292
+ chunks.push(chunk);
293
+ });
294
+ deleteJourneyCmd.stderr.on('end', () => {
295
+ const output = Buffer.concat(chunks)
296
+ .toString()
297
+ .replace(ansiEscapeCodes, '');
298
+ try {
299
+ for (const str of expected) {
300
+ expect(output).toContain(str);
301
+ }
302
+ done();
303
+ } catch (error) {
304
+ done(error);
305
+ }
306
+ });
307
+ },
308
+ // increase timeout for long-running test
309
+ 10 * 1000
310
+ );
311
+
312
+ it('"frodo journey delete -a --no-deep": should delete all journeys but none of their nodes', (done) => {
313
+ const deleteJourneyCmd = spawn('frodo', [
314
+ 'journey',
315
+ 'delete',
316
+ '-a',
317
+ '--no-deep',
318
+ 'frodo-dev',
319
+ ]);
320
+ const expected = [
321
+ '[========================================] 100% | 8/8 | Deleted 8/8 journeys and 0/0 nodes.',
322
+ '',
323
+ ].join('\n');
324
+ const chunks = [];
325
+ deleteJourneyCmd.stderr.on('data', (chunk) => {
326
+ chunks.push(chunk);
327
+ });
328
+ deleteJourneyCmd.stderr.on('end', () => {
329
+ const output = Buffer.concat(chunks)
330
+ .toString()
331
+ .replace(ansiEscapeCodes, '');
332
+ try {
333
+ expect(output).toContain(expected);
334
+ done();
335
+ } catch (error) {
336
+ done(error);
337
+ }
338
+ });
339
+ });
340
+
341
+ it('"frodo journey delete -a --no-deep --verbose": should delete all journeys but none of their nodes with verbose output', (done) => {
342
+ const deleteJourneyCmd = spawn('frodo', [
343
+ 'journey',
344
+ 'delete',
345
+ '-a',
346
+ '--no-deep',
347
+ '--verbose',
348
+ 'frodo-dev',
349
+ ]);
350
+ const expected = [
351
+ '[----------------------------------------] 0% | 0/8 | Deleting journeys...\n',
352
+ 'Deleted ResetPassword (tree)\n',
353
+ 'Deleted Registration (tree)\n',
354
+ 'Deleted PasswordGrant (tree)\n',
355
+ 'Deleted ProgressiveProfile (tree)\n',
356
+ 'Deleted ForgottenUsername (tree)\n',
357
+ 'Deleted deleteMe (tree)\n',
358
+ 'Deleted UpdatePassword (tree)\n',
359
+ 'Deleted Login (tree)\n',
360
+ '[========================================] 100% | 8/8 | Deleted 8/8 journeys and 0/0 nodes.\n',
361
+ ];
362
+ const chunks = [];
363
+ deleteJourneyCmd.stderr.on('data', (chunk) => {
364
+ chunks.push(chunk);
365
+ });
366
+ deleteJourneyCmd.stderr.on('end', () => {
367
+ const output = Buffer.concat(chunks)
368
+ .toString()
369
+ .replace(ansiEscapeCodes, '');
370
+ try {
371
+ for (const str of expected) {
372
+ expect(output).toContain(str);
373
+ }
374
+ done();
375
+ } catch (error) {
376
+ done(error);
377
+ }
378
+ });
379
+ });
380
+ });
@@ -1,10 +1,12 @@
1
1
  import fs from 'fs';
2
2
  import { Command, Option } from 'commander';
3
3
  import { Authenticate, Journey, state } from '@rockcarver/frodo-lib';
4
+ import { describeJourney } from '../../ops/JourneyOps';
4
5
  import * as common from '../cmd_common.js';
5
6
 
6
7
  const { getTokens } = Authenticate;
7
- const { getJourneys, exportJourney, describeJourney } = Journey;
8
+ const { getJourneys, exportJourney, createFileParamTreeExportResolver } =
9
+ Journey;
8
10
 
9
11
  const program = new Command('frodo journey describe');
10
12
 
@@ -32,12 +34,12 @@ program
32
34
  'Name of the file to write the exported journey(s) to. Ignored with -A.'
33
35
  )
34
36
  )
35
- // .addOption(
36
- // new Option(
37
- // '-o, --override-version <version>',
38
- // "Override version. Notation: 'X.Y.Z' e.g. '7.1.0'. Override detected version with any version. This is helpful in order to check if journeys in one environment would be compatible running in another environment (e.g. in preparation of migrating from on-prem to ForgeRock Identity Cloud. Only impacts these actions: -d, -l."
39
- // )
40
- // )
37
+ .addOption(
38
+ new Option(
39
+ '-o, --override-version <version>',
40
+ "Override version. Notation: '<major>.<minor>.<patch>' e.g. '7.2.0'. Override detected version with any version. This is helpful in order to check if journeys in one environment would be compatible running in another environment (e.g. in preparation of migrating from on-prem to ForgeRock Identity Cloud."
41
+ )
42
+ )
41
43
  .action(
42
44
  // implement command logic inside action handler
43
45
  async (host, realm, user, password, options) => {
@@ -59,9 +61,51 @@ program
59
61
  }
60
62
  console.log(`Describing local journey file ${options.file}...`);
61
63
  try {
62
- const data = fs.readFileSync(options.file, 'utf8');
63
- const journeyData = JSON.parse(data);
64
- describeJourney(journeyData);
64
+ // override version
65
+ if (typeof options.overrideVersion !== 'undefined') {
66
+ state.default.session.setAmVersion(options.overrideVersion);
67
+ }
68
+ const fileData = JSON.parse(fs.readFileSync(options.file, 'utf8'));
69
+ let journeyData;
70
+ // single or multi tree export?
71
+ // multi - by id
72
+ if (
73
+ typeof options.journeyId !== 'undefined' &&
74
+ fileData.trees &&
75
+ fileData.trees[options.journeyId]
76
+ ) {
77
+ journeyData = fileData.trees[options.journeyId];
78
+ }
79
+ // multi - first
80
+ else if (typeof options.journeyId === 'undefined' && fileData.trees) {
81
+ [journeyData] = Object.values(fileData.trees);
82
+ }
83
+ // single - by id
84
+ else if (
85
+ typeof options.journeyId !== 'undefined' &&
86
+ options.journeyId === fileData.tree?._id
87
+ ) {
88
+ journeyData = fileData;
89
+ }
90
+ // single
91
+ else if (
92
+ typeof options.journeyId === 'undefined' &&
93
+ fileData.tree?._id
94
+ ) {
95
+ journeyData = fileData;
96
+ }
97
+ // no journey/tree found
98
+ else {
99
+ throw new Error(
100
+ typeof options.journeyId === 'undefined'
101
+ ? `No journey found in ${options.file}`
102
+ : `Journey '${options.journeyId}' not found in ${options.file}`
103
+ );
104
+ }
105
+ describeJourney(
106
+ journeyData,
107
+ createFileParamTreeExportResolver(options.file)
108
+ );
65
109
  } catch (error) {
66
110
  console.log(error.message);
67
111
  process.exitCode = 1;
@@ -70,12 +114,16 @@ program
70
114
  console.log(
71
115
  `Describing journey(s) in realm "${state.default.session.getRealm()}"...`
72
116
  );
117
+ // override version
118
+ if (typeof options.overrideVersion !== 'undefined') {
119
+ state.default.session.setAmVersion(options.overrideVersion);
120
+ }
73
121
  if (typeof options.journeyId === 'undefined') {
74
- let journeys = [];
122
+ let journeys: any[] = [];
75
123
  journeys = await getJourneys();
76
124
  for (const journey of journeys) {
77
125
  try {
78
- // eslint-disable-next-line no-await-in-loop
126
+ // eslint-disable-next-line no-await-in-loop, dot-notation
79
127
  const treeData = await exportJourney(journey['_id']);
80
128
  describeJourney(treeData);
81
129
  } catch (error) {
@@ -0,0 +1,142 @@
1
+ // import { jest } from '@jest/globals';
2
+ import { spawn, spawnSync } from 'child_process';
3
+
4
+ const ansiEscapeCodes =
5
+ // eslint-disable-next-line no-control-regex
6
+ /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
7
+
8
+ /**
9
+ * delete all journeys and import baseline and additional test journeys
10
+ */
11
+ beforeAll(async () => {
12
+ // delete all journeys
13
+ const deleteJourneysCmd = spawnSync('frodo', [
14
+ 'journey',
15
+ 'delete',
16
+ '--all',
17
+ 'frodo-dev',
18
+ ]);
19
+ if (deleteJourneysCmd.status > 0) {
20
+ console.error(deleteJourneysCmd.stderr.toString());
21
+ console.log(deleteJourneysCmd.stdout.toString());
22
+ }
23
+
24
+ // import baseline journeys
25
+ const importBaselineJourneysCmd = spawnSync(
26
+ 'frodo',
27
+ ['journey', 'import', '--all-separate', 'frodo-dev'],
28
+ {
29
+ cwd: `test/e2e/journey/baseline`,
30
+ }
31
+ );
32
+ if (importBaselineJourneysCmd.status > 0) {
33
+ console.error(importBaselineJourneysCmd.stderr.toString());
34
+ console.log(importBaselineJourneysCmd.stdout.toString());
35
+ }
36
+
37
+ // import additional test journeys
38
+ const importTestJourneysCmd = spawnSync(
39
+ 'frodo',
40
+ ['journey', 'import', '--all-separate', 'frodo-dev'],
41
+ {
42
+ cwd: `test/e2e/journey/list`,
43
+ }
44
+ );
45
+ if (importTestJourneysCmd.status > 0) {
46
+ console.error(importTestJourneysCmd.stderr.toString());
47
+ console.log(importTestJourneysCmd.stdout.toString());
48
+ }
49
+ });
50
+
51
+ describe('frodo journey list', () => {
52
+ it('"frodo journey list": should list the names of the default journeys', (done) => {
53
+ const journeyList = spawn('frodo', ['journey', 'list', 'frodo-dev']);
54
+ const expected = [
55
+ 'Disabled',
56
+ 'ForgottenUsername',
57
+ 'Login',
58
+ 'PasswordGrant',
59
+ 'ProgressiveProfile',
60
+ 'Registration',
61
+ 'ResetPassword',
62
+ 'UpdatePassword',
63
+ '',
64
+ ].join('\n');
65
+
66
+ const chunks = [];
67
+ journeyList.stdout.on('data', (chunk) => {
68
+ chunks.push(chunk);
69
+ });
70
+
71
+ journeyList.stdout.on('end', () => {
72
+ const output = Buffer.concat(chunks).toString();
73
+ try {
74
+ expect(output).toBe(expected);
75
+ done();
76
+ } catch (error) {
77
+ done(error);
78
+ }
79
+ });
80
+ });
81
+
82
+ const expectedLong = [
83
+ 'Listing journeys in realm "alpha"...',
84
+ 'Name │Status │Tags ',
85
+ 'Disabled │disabled│Prototype ',
86
+ 'ForgottenUsername │enabled │Username Reset ',
87
+ 'Login │enabled │Authentication ',
88
+ 'PasswordGrant │enabled │ ',
89
+ 'ProgressiveProfile│enabled │Progressive Profile',
90
+ 'Registration │enabled │Registration ',
91
+ 'ResetPassword │enabled │Password Reset ',
92
+ 'UpdatePassword │enabled │Password Reset ',
93
+ '',
94
+ ].join('\n');
95
+
96
+ it('"frodo journey list -l": should list the names, status, and tags of the default journeys', (done) => {
97
+ const journeyList = spawn('frodo', ['journey', 'list', '-l', 'frodo-dev']);
98
+
99
+ const chunks = [];
100
+ journeyList.stdout.on('data', (chunk) => {
101
+ chunks.push(chunk);
102
+ });
103
+
104
+ journeyList.stdout.on('end', () => {
105
+ const output = Buffer.concat(chunks)
106
+ .toString()
107
+ .replace(ansiEscapeCodes, '');
108
+ try {
109
+ expect(output).toBe(expectedLong);
110
+ done();
111
+ } catch (error) {
112
+ done(error);
113
+ }
114
+ });
115
+ });
116
+
117
+ it('"frodo journey list --long": should list the names, status, and tags of the default journeys', (done) => {
118
+ const journeyList = spawn('frodo', [
119
+ 'journey',
120
+ 'list',
121
+ '--long',
122
+ 'frodo-dev',
123
+ ]);
124
+
125
+ const chunks = [];
126
+ journeyList.stdout.on('data', (chunk) => {
127
+ chunks.push(chunk);
128
+ });
129
+
130
+ journeyList.stdout.on('end', () => {
131
+ const output = Buffer.concat(chunks)
132
+ .toString()
133
+ .replace(ansiEscapeCodes, '');
134
+ try {
135
+ expect(output).toBe(expectedLong);
136
+ done();
137
+ } catch (error) {
138
+ done(error);
139
+ }
140
+ });
141
+ });
142
+ });
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes