unleash-server 4.1.4 → 4.2.0-beta.1

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 (443) hide show
  1. package/README.md +3 -2
  2. package/dist/lib/addons/datadog-definition.js +7 -0
  3. package/dist/lib/addons/datadog-definition.js.map +1 -1
  4. package/dist/lib/addons/datadog.d.ts +5 -0
  5. package/dist/lib/addons/datadog.js +53 -0
  6. package/dist/lib/addons/datadog.js.map +1 -1
  7. package/dist/lib/addons/datadog.test.js +26 -1
  8. package/dist/lib/addons/datadog.test.js.map +1 -1
  9. package/dist/lib/addons/slack-definition.js +7 -0
  10. package/dist/lib/addons/slack-definition.js.map +1 -1
  11. package/dist/lib/addons/slack.d.ts +5 -0
  12. package/dist/lib/addons/slack.js +62 -9
  13. package/dist/lib/addons/slack.js.map +1 -1
  14. package/dist/lib/addons/slack.test.js +25 -0
  15. package/dist/lib/addons/slack.test.js.map +1 -1
  16. package/dist/lib/addons/teams-definition.js +7 -0
  17. package/dist/lib/addons/teams-definition.js.map +1 -1
  18. package/dist/lib/addons/teams.d.ts +5 -0
  19. package/dist/lib/addons/teams.js +54 -1
  20. package/dist/lib/addons/teams.js.map +1 -1
  21. package/dist/lib/addons/teams.test.js +25 -0
  22. package/dist/lib/addons/teams.test.js.map +1 -1
  23. package/dist/lib/addons/webhook-definition.js +8 -0
  24. package/dist/lib/addons/webhook-definition.js.map +1 -1
  25. package/dist/lib/app.test.js +11 -7
  26. package/dist/lib/app.test.js.map +1 -1
  27. package/dist/lib/create-config.js +4 -1
  28. package/dist/lib/create-config.js.map +1 -1
  29. package/dist/lib/db/api-token-store.d.ts +2 -1
  30. package/dist/lib/db/api-token-store.js +5 -0
  31. package/dist/lib/db/api-token-store.js.map +1 -1
  32. package/dist/lib/db/client-instance-store.js +5 -2
  33. package/dist/lib/db/client-instance-store.js.map +1 -1
  34. package/dist/lib/db/client-metrics-store-v2.d.ts +19 -0
  35. package/dist/lib/db/client-metrics-store-v2.js +126 -0
  36. package/dist/lib/db/client-metrics-store-v2.js.map +1 -0
  37. package/dist/lib/db/client-metrics-store.d.ts +6 -0
  38. package/dist/lib/db/client-metrics-store.js +6 -1
  39. package/dist/lib/db/client-metrics-store.js.map +1 -1
  40. package/dist/lib/db/environment-store.d.ts +7 -7
  41. package/dist/lib/db/environment-store.js +59 -54
  42. package/dist/lib/db/environment-store.js.map +1 -1
  43. package/dist/lib/db/event-store.d.ts +5 -2
  44. package/dist/lib/db/event-store.js +27 -4
  45. package/dist/lib/db/event-store.js.map +1 -1
  46. package/dist/lib/db/feature-environment-store.d.ts +9 -6
  47. package/dist/lib/db/feature-environment-store.js +66 -20
  48. package/dist/lib/db/feature-environment-store.js.map +1 -1
  49. package/dist/lib/db/feature-strategy-store.d.ts +7 -11
  50. package/dist/lib/db/feature-strategy-store.js +84 -147
  51. package/dist/lib/db/feature-strategy-store.js.map +1 -1
  52. package/dist/lib/db/feature-toggle-client-store.d.ts +26 -0
  53. package/dist/lib/db/feature-toggle-client-store.js +104 -0
  54. package/dist/lib/db/feature-toggle-client-store.js.map +1 -0
  55. package/dist/lib/db/feature-toggle-store.d.ts +10 -22
  56. package/dist/lib/db/feature-toggle-store.js +9 -42
  57. package/dist/lib/db/feature-toggle-store.js.map +1 -1
  58. package/dist/lib/db/index.js +4 -0
  59. package/dist/lib/db/index.js.map +1 -1
  60. package/dist/lib/db/project-store.d.ts +4 -6
  61. package/dist/lib/db/project-store.js +7 -43
  62. package/dist/lib/db/project-store.js.map +1 -1
  63. package/dist/lib/event-hook.test.js +8 -7
  64. package/dist/lib/event-hook.test.js.map +1 -1
  65. package/dist/lib/logger.test.js +26 -4
  66. package/dist/lib/logger.test.js.map +1 -1
  67. package/dist/lib/middleware/api-token-middleware.js +10 -2
  68. package/dist/lib/middleware/api-token-middleware.js.map +1 -1
  69. package/dist/lib/middleware/api-token-middleware.test.js +37 -1
  70. package/dist/lib/middleware/api-token-middleware.test.js.map +1 -1
  71. package/dist/lib/middleware/demo-authentication.js +1 -1
  72. package/dist/lib/middleware/demo-authentication.js.map +1 -1
  73. package/dist/lib/middleware/oss-authentication.js +0 -3
  74. package/dist/lib/middleware/oss-authentication.js.map +1 -1
  75. package/dist/lib/middleware/rbac-middleware.js +2 -2
  76. package/dist/lib/middleware/rbac-middleware.js.map +1 -1
  77. package/dist/lib/middleware/rbac-middleware.test.js +39 -0
  78. package/dist/lib/middleware/rbac-middleware.test.js.map +1 -1
  79. package/dist/lib/routes/admin-api/addon.d.ts +4 -3
  80. package/dist/lib/routes/admin-api/addon.js +4 -4
  81. package/dist/lib/routes/admin-api/addon.js.map +1 -1
  82. package/dist/lib/routes/admin-api/api-token-controller.js +10 -38
  83. package/dist/lib/routes/admin-api/api-token-controller.js.map +1 -1
  84. package/dist/lib/routes/admin-api/archive.d.ts +4 -3
  85. package/dist/lib/routes/admin-api/archive.js +3 -3
  86. package/dist/lib/routes/admin-api/archive.js.map +1 -1
  87. package/dist/lib/routes/admin-api/client-metrics.d.ts +12 -0
  88. package/dist/lib/routes/admin-api/client-metrics.js +35 -0
  89. package/dist/lib/routes/admin-api/client-metrics.js.map +1 -0
  90. package/dist/lib/routes/admin-api/context.d.ts +4 -3
  91. package/dist/lib/routes/admin-api/context.js +4 -4
  92. package/dist/lib/routes/admin-api/context.js.map +1 -1
  93. package/dist/lib/routes/admin-api/environments-controller.d.ts +4 -4
  94. package/dist/lib/routes/admin-api/environments-controller.js +17 -43
  95. package/dist/lib/routes/admin-api/environments-controller.js.map +1 -1
  96. package/dist/lib/routes/admin-api/event.js +7 -1
  97. package/dist/lib/routes/admin-api/event.js.map +1 -1
  98. package/dist/lib/routes/admin-api/feature.d.ts +11 -10
  99. package/dist/lib/routes/admin-api/feature.js +26 -24
  100. package/dist/lib/routes/admin-api/feature.js.map +1 -1
  101. package/dist/lib/routes/admin-api/index.js +2 -0
  102. package/dist/lib/routes/admin-api/index.js.map +1 -1
  103. package/dist/lib/routes/admin-api/metrics.js +25 -66
  104. package/dist/lib/routes/admin-api/metrics.js.map +1 -1
  105. package/dist/lib/routes/admin-api/project/environments.js +6 -15
  106. package/dist/lib/routes/admin-api/project/environments.js.map +1 -1
  107. package/dist/lib/routes/admin-api/project/features.d.ts +33 -11
  108. package/dist/lib/routes/admin-api/project/features.js +103 -35
  109. package/dist/lib/routes/admin-api/project/features.js.map +1 -1
  110. package/dist/lib/routes/admin-api/project/health-report.js +7 -18
  111. package/dist/lib/routes/admin-api/project/health-report.js.map +1 -1
  112. package/dist/lib/routes/admin-api/project/index.d.ts +3 -0
  113. package/dist/lib/routes/admin-api/project/index.js +8 -0
  114. package/dist/lib/routes/admin-api/project/index.js.map +1 -1
  115. package/dist/lib/routes/admin-api/state.d.ts +2 -1
  116. package/dist/lib/routes/admin-api/state.js +5 -4
  117. package/dist/lib/routes/admin-api/state.js.map +1 -1
  118. package/dist/lib/routes/admin-api/strategy.d.ts +1 -1
  119. package/dist/lib/routes/admin-api/strategy.js +24 -22
  120. package/dist/lib/routes/admin-api/strategy.js.map +1 -1
  121. package/dist/lib/routes/admin-api/tag-type.d.ts +4 -3
  122. package/dist/lib/routes/admin-api/tag-type.js +19 -50
  123. package/dist/lib/routes/admin-api/tag-type.js.map +1 -1
  124. package/dist/lib/routes/admin-api/tag.d.ts +3 -2
  125. package/dist/lib/routes/admin-api/tag.js +3 -4
  126. package/dist/lib/routes/admin-api/tag.js.map +1 -1
  127. package/dist/lib/routes/admin-api/user-admin.js +11 -37
  128. package/dist/lib/routes/admin-api/user-admin.js.map +1 -1
  129. package/dist/lib/routes/api-def.d.ts +49 -52
  130. package/dist/lib/routes/api-def.js +13 -9
  131. package/dist/lib/routes/api-def.js.map +1 -1
  132. package/dist/lib/routes/client-api/feature.d.ts +7 -8
  133. package/dist/lib/routes/client-api/feature.js +39 -27
  134. package/dist/lib/routes/client-api/feature.js.map +1 -1
  135. package/dist/lib/routes/client-api/feature.test.js +10 -10
  136. package/dist/lib/routes/client-api/feature.test.js.map +1 -1
  137. package/dist/lib/routes/client-api/metrics.d.ts +8 -3
  138. package/dist/lib/routes/client-api/metrics.js +28 -16
  139. package/dist/lib/routes/client-api/metrics.js.map +1 -1
  140. package/dist/lib/routes/client-api/metrics.test.js +27 -9
  141. package/dist/lib/routes/client-api/metrics.test.js.map +1 -1
  142. package/dist/lib/routes/client-api/register.d.ts +4 -2
  143. package/dist/lib/routes/client-api/register.js +16 -14
  144. package/dist/lib/routes/client-api/register.js.map +1 -1
  145. package/dist/lib/routes/controller.d.ts +1 -0
  146. package/dist/lib/routes/controller.js +3 -0
  147. package/dist/lib/routes/controller.js.map +1 -1
  148. package/dist/lib/routes/index.js +5 -5
  149. package/dist/lib/routes/index.js.map +1 -1
  150. package/dist/lib/routes/unleash-types.d.ts +1 -2
  151. package/dist/lib/routes/util.js +1 -0
  152. package/dist/lib/routes/util.js.map +1 -1
  153. package/dist/lib/schema/api-token-schema.d.ts +2 -0
  154. package/dist/lib/schema/api-token-schema.js +28 -0
  155. package/dist/lib/schema/api-token-schema.js.map +1 -0
  156. package/dist/lib/schema/feature-schema.test.js +17 -16
  157. package/dist/lib/schema/feature-schema.test.js.map +1 -1
  158. package/dist/lib/schema/project-schema.d.ts +2 -0
  159. package/dist/lib/schema/project-schema.js +12 -0
  160. package/dist/lib/schema/project-schema.js.map +1 -0
  161. package/dist/lib/server-impl.d.ts +2 -2
  162. package/dist/lib/server-impl.js +9 -6
  163. package/dist/lib/server-impl.js.map +1 -1
  164. package/dist/lib/server-impl.test.js +28 -21
  165. package/dist/lib/server-impl.test.js.map +1 -1
  166. package/dist/lib/services/access-service.d.ts +1 -1
  167. package/dist/lib/services/access-service.js.map +1 -1
  168. package/dist/lib/services/api-token-service.d.ts +3 -8
  169. package/dist/lib/services/api-token-service.js +43 -8
  170. package/dist/lib/services/api-token-service.js.map +1 -1
  171. package/dist/lib/services/client-metrics/client-metrics-schema.js +1 -0
  172. package/dist/lib/services/client-metrics/client-metrics-schema.js.map +1 -1
  173. package/dist/lib/services/client-metrics/client-metrics-service-v2.d.ts +16 -0
  174. package/dist/lib/services/client-metrics/client-metrics-service-v2.js +68 -0
  175. package/dist/lib/services/client-metrics/client-metrics-service-v2.js.map +1 -0
  176. package/dist/lib/services/client-metrics/index.d.ts +0 -1
  177. package/dist/lib/services/client-metrics/index.js +5 -3
  178. package/dist/lib/services/client-metrics/index.js.map +1 -1
  179. package/dist/lib/services/client-metrics/register-schema.js +1 -0
  180. package/dist/lib/services/client-metrics/register-schema.js.map +1 -1
  181. package/dist/lib/services/context-schema.d.ts +3 -3
  182. package/dist/lib/services/context-schema.js +15 -11
  183. package/dist/lib/services/context-schema.js.map +1 -1
  184. package/dist/lib/services/environment-service.d.ts +4 -5
  185. package/dist/lib/services/environment-service.js +14 -14
  186. package/dist/lib/services/environment-service.js.map +1 -1
  187. package/dist/lib/services/event-service.d.ts +1 -0
  188. package/dist/lib/services/event-service.js +4 -3
  189. package/dist/lib/services/event-service.js.map +1 -1
  190. package/dist/lib/services/feature-toggle-service-v2.d.ts +33 -12
  191. package/dist/lib/services/feature-toggle-service-v2.js +200 -55
  192. package/dist/lib/services/feature-toggle-service-v2.js.map +1 -1
  193. package/dist/lib/services/index.js +4 -1
  194. package/dist/lib/services/index.js.map +1 -1
  195. package/dist/lib/services/project-health-service.d.ts +3 -1
  196. package/dist/lib/services/project-health-service.js +7 -3
  197. package/dist/lib/services/project-health-service.js.map +1 -1
  198. package/dist/lib/services/project-schema.d.ts +2 -3
  199. package/dist/lib/services/project-schema.js +12 -7
  200. package/dist/lib/services/project-schema.js.map +1 -1
  201. package/dist/lib/services/project-service.d.ts +4 -2
  202. package/dist/lib/services/project-service.js +21 -11
  203. package/dist/lib/services/project-service.js.map +1 -1
  204. package/dist/lib/services/state-schema.d.ts +2 -0
  205. package/dist/lib/services/state-schema.js +16 -6
  206. package/dist/lib/services/state-schema.js.map +1 -1
  207. package/dist/lib/services/state-service.d.ts +7 -0
  208. package/dist/lib/services/state-service.js +69 -11
  209. package/dist/lib/services/state-service.js.map +1 -1
  210. package/dist/lib/services/state-service.test.js +72 -27
  211. package/dist/lib/services/state-service.test.js.map +1 -1
  212. package/dist/lib/services/state-util.js +1 -1
  213. package/dist/lib/services/state-util.js.map +1 -1
  214. package/dist/lib/types/api-user.d.ts +11 -4
  215. package/dist/lib/types/api-user.js +4 -1
  216. package/dist/lib/types/api-user.js.map +1 -1
  217. package/dist/lib/types/events.d.ts +7 -0
  218. package/dist/lib/types/events.js +9 -1
  219. package/dist/lib/types/events.js.map +1 -1
  220. package/dist/lib/types/model.d.ts +27 -8
  221. package/dist/lib/types/model.js.map +1 -1
  222. package/dist/lib/types/models/api-token.d.ts +19 -0
  223. package/dist/lib/types/models/api-token.js +10 -0
  224. package/dist/lib/types/models/api-token.js.map +1 -0
  225. package/dist/lib/types/models/metrics.d.ts +11 -0
  226. package/dist/lib/types/models/metrics.js +3 -0
  227. package/dist/lib/types/models/metrics.js.map +1 -0
  228. package/dist/lib/types/permissions.d.ts +2 -0
  229. package/dist/lib/types/permissions.js +3 -1
  230. package/dist/lib/types/permissions.js.map +1 -1
  231. package/dist/lib/types/services.d.ts +2 -0
  232. package/dist/lib/types/stores/api-token-store.d.ts +1 -14
  233. package/dist/lib/types/stores/api-token-store.js +0 -6
  234. package/dist/lib/types/stores/api-token-store.js.map +1 -1
  235. package/dist/lib/types/stores/client-instance-store.d.ts +1 -0
  236. package/dist/lib/types/stores/client-metrics-store-v2.d.ts +17 -0
  237. package/dist/lib/types/stores/client-metrics-store-v2.js +3 -0
  238. package/dist/lib/types/stores/client-metrics-store-v2.js.map +1 -0
  239. package/dist/lib/types/stores/environment-store.d.ts +6 -6
  240. package/dist/lib/types/stores/event-store.d.ts +1 -0
  241. package/dist/lib/types/stores/feature-environment-store.d.ts +9 -6
  242. package/dist/lib/types/stores/feature-strategies-store.d.ts +6 -12
  243. package/dist/lib/types/stores/feature-toggle-client-store.d.ts +5 -0
  244. package/dist/lib/types/stores/feature-toggle-client-store.js +3 -0
  245. package/dist/lib/types/stores/feature-toggle-client-store.js.map +1 -0
  246. package/dist/lib/types/stores/feature-toggle-store.d.ts +7 -14
  247. package/dist/lib/types/stores/project-store.d.ts +5 -2
  248. package/dist/lib/types/stores.d.ts +4 -0
  249. package/dist/lib/util/constants.d.ts +1 -0
  250. package/dist/lib/util/constants.js +2 -1
  251. package/dist/lib/util/constants.js.map +1 -1
  252. package/dist/lib/util/extract-user.d.ts +2 -0
  253. package/dist/lib/util/extract-user.js +8 -0
  254. package/dist/lib/util/extract-user.js.map +1 -0
  255. package/dist/lib/util/graceful-shutdown.js +1 -1
  256. package/dist/lib/util/graceful-shutdown.js.map +1 -1
  257. package/dist/lib/util/snakeCase.d.ts +6 -0
  258. package/dist/lib/util/snakeCase.js +28 -0
  259. package/dist/lib/util/snakeCase.js.map +1 -0
  260. package/dist/{test/e2e/api/admin/boostrap.test.d.ts → lib/util/snakeCase.test.d.ts} +0 -0
  261. package/dist/lib/util/snakeCase.test.js +23 -0
  262. package/dist/lib/util/snakeCase.test.js.map +1 -0
  263. package/dist/migrations/20210831072631-add-sort-order-and-type-to-env.d.ts +5 -0
  264. package/dist/migrations/20210831072631-add-sort-order-and-type-to-env.js +14 -0
  265. package/dist/migrations/20210831072631-add-sort-order-and-type-to-env.js.map +1 -0
  266. package/dist/migrations/20210907124058-add-dbcritic-indices.d.ts +5 -0
  267. package/dist/migrations/20210907124058-add-dbcritic-indices.js +30 -0
  268. package/dist/migrations/20210907124058-add-dbcritic-indices.js.map +1 -0
  269. package/dist/migrations/20210907124850-add-dbcritic-primary-keys.d.ts +5 -0
  270. package/dist/migrations/20210907124850-add-dbcritic-primary-keys.js +18 -0
  271. package/dist/migrations/20210907124850-add-dbcritic-primary-keys.js.map +1 -0
  272. package/dist/migrations/20210908100701-add-enabled-to-environments.d.ts +5 -0
  273. package/dist/migrations/20210908100701-add-enabled-to-environments.js +14 -0
  274. package/dist/migrations/20210908100701-add-enabled-to-environments.js.map +1 -0
  275. package/dist/migrations/20210909085651-add-protected-field-to-environments.d.ts +5 -0
  276. package/dist/migrations/20210909085651-add-protected-field-to-environments.js +15 -0
  277. package/dist/migrations/20210909085651-add-protected-field-to-environments.js.map +1 -0
  278. package/dist/migrations/20210913103159-api-keys-scoping.d.ts +2 -0
  279. package/dist/migrations/20210913103159-api-keys-scoping.js +13 -0
  280. package/dist/migrations/20210913103159-api-keys-scoping.js.map +1 -0
  281. package/dist/migrations/20210915122001-add-project-and-environment-columns-to-events.d.ts +2 -0
  282. package/dist/migrations/20210915122001-add-project-and-environment-columns-to-events.js +22 -0
  283. package/dist/migrations/20210915122001-add-project-and-environment-columns-to-events.js.map +1 -0
  284. package/dist/migrations/20210920104218-rename-global-env-to-default-env.d.ts +2 -0
  285. package/dist/migrations/20210920104218-rename-global-env-to-default-env.js +25 -0
  286. package/dist/migrations/20210920104218-rename-global-env-to-default-env.js.map +1 -0
  287. package/dist/migrations/20210921105032-client-api-tokens-default.d.ts +2 -0
  288. package/dist/migrations/20210921105032-client-api-tokens-default.js +13 -0
  289. package/dist/migrations/20210921105032-client-api-tokens-default.js.map +1 -0
  290. package/dist/migrations/20210922084509-add-non-null-constraint-to-environment-type.d.ts +2 -0
  291. package/dist/migrations/20210922084509-add-non-null-constraint-to-environment-type.js +10 -0
  292. package/dist/migrations/20210922084509-add-non-null-constraint-to-environment-type.js.map +1 -0
  293. package/dist/migrations/20210922120521-add-tag-type-permission.d.ts +2 -0
  294. package/dist/migrations/20210922120521-add-tag-type-permission.js +19 -0
  295. package/dist/migrations/20210922120521-add-tag-type-permission.js.map +1 -0
  296. package/dist/migrations/20210928065411-remove-displayname-from-environments.d.ts +2 -0
  297. package/dist/migrations/20210928065411-remove-displayname-from-environments.js +10 -0
  298. package/dist/migrations/20210928065411-remove-displayname-from-environments.js.map +1 -0
  299. package/dist/migrations/20210928080601-add-development-and-production-environments.d.ts +2 -0
  300. package/dist/migrations/20210928080601-add-development-and-production-environments.js +16 -0
  301. package/dist/migrations/20210928080601-add-development-and-production-environments.js.map +1 -0
  302. package/dist/migrations/20210928082228-connect-default-environment-to-all-existing-projects.d.ts +2 -0
  303. package/dist/migrations/20210928082228-connect-default-environment-to-all-existing-projects.js +16 -0
  304. package/dist/migrations/20210928082228-connect-default-environment-to-all-existing-projects.js.map +1 -0
  305. package/dist/migrations/20211004104917-client-metrics-env.d.ts +2 -0
  306. package/dist/migrations/20211004104917-client-metrics-env.js +22 -0
  307. package/dist/migrations/20211004104917-client-metrics-env.js.map +1 -0
  308. package/dist/migrations/20211011094226-add-environment-to-client-instances.d.ts +5 -0
  309. package/dist/migrations/20211011094226-add-environment-to-client-instances.js +21 -0
  310. package/dist/migrations/20211011094226-add-environment-to-client-instances.js.map +1 -0
  311. package/dist/migrator.d.ts +3 -4
  312. package/dist/migrator.js +19 -5
  313. package/dist/migrator.js.map +1 -1
  314. package/dist/server-dev.js +5 -0
  315. package/dist/server-dev.js.map +1 -1
  316. package/dist/test/e2e/api/admin/api-token.auth.e2e.test.js +4 -4
  317. package/dist/test/e2e/api/admin/api-token.auth.e2e.test.js.map +1 -1
  318. package/dist/test/e2e/api/admin/api-token.e2e.test.js +159 -10
  319. package/dist/test/e2e/api/admin/api-token.e2e.test.js.map +1 -1
  320. package/dist/test/e2e/api/admin/archive.test.js.map +1 -1
  321. package/dist/test/e2e/api/admin/{project/feature.strategy.e2e.test.d.ts → bootstrap.test.d.ts} +0 -0
  322. package/dist/test/e2e/api/admin/{boostrap.test.js → bootstrap.test.js} +2 -2
  323. package/dist/test/e2e/api/admin/bootstrap.test.js.map +1 -0
  324. package/dist/test/e2e/api/admin/client-metrics.e2e.test.d.ts +1 -0
  325. package/dist/test/e2e/api/admin/client-metrics.e2e.test.js +219 -0
  326. package/dist/test/e2e/api/admin/client-metrics.e2e.test.js.map +1 -0
  327. package/dist/test/e2e/api/admin/environment.test.js +80 -53
  328. package/dist/test/e2e/api/admin/environment.test.js.map +1 -1
  329. package/dist/test/e2e/api/admin/event.e2e.test.js +28 -0
  330. package/dist/test/e2e/api/admin/event.e2e.test.js.map +1 -1
  331. package/dist/test/e2e/api/admin/feature.e2e.test.js +69 -63
  332. package/dist/test/e2e/api/admin/feature.e2e.test.js.map +1 -1
  333. package/dist/test/e2e/api/admin/project/environments.e2e.test.d.ts +1 -0
  334. package/dist/test/e2e/api/admin/project/environments.e2e.test.js +65 -0
  335. package/dist/test/e2e/api/admin/project/environments.e2e.test.js.map +1 -0
  336. package/dist/test/e2e/api/admin/project/features.e2e.test.d.ts +1 -0
  337. package/dist/test/e2e/api/admin/project/features.e2e.test.js +1267 -0
  338. package/dist/test/e2e/api/admin/project/features.e2e.test.js.map +1 -0
  339. package/dist/test/e2e/api/admin/project/project.health.e2e.test.js +76 -0
  340. package/dist/test/e2e/api/admin/project/project.health.e2e.test.js.map +1 -1
  341. package/dist/test/e2e/api/admin/project/projects.e2e.test.d.ts +1 -0
  342. package/dist/test/e2e/api/admin/project/projects.e2e.test.js +30 -0
  343. package/dist/test/e2e/api/admin/project/projects.e2e.test.js.map +1 -0
  344. package/dist/test/e2e/api/admin/state.e2e.test.js +161 -0
  345. package/dist/test/e2e/api/admin/state.e2e.test.js.map +1 -1
  346. package/dist/test/e2e/api/client/feature.e2e.test.js +83 -29
  347. package/dist/test/e2e/api/client/feature.e2e.test.js.map +1 -1
  348. package/dist/test/e2e/api/client/feature.env.disabled.e2e.test.d.ts +1 -0
  349. package/dist/test/e2e/api/client/feature.env.disabled.e2e.test.js +49 -0
  350. package/dist/test/e2e/api/client/feature.env.disabled.e2e.test.js.map +1 -0
  351. package/dist/test/e2e/api/client/feature.token.access.e2e.test.d.ts +1 -0
  352. package/dist/test/e2e/api/client/feature.token.access.e2e.test.js +156 -0
  353. package/dist/test/e2e/api/client/feature.token.access.e2e.test.js.map +1 -0
  354. package/dist/test/e2e/api/client/metrics.e2e.access.e2e.test.d.ts +1 -0
  355. package/dist/test/e2e/api/client/metrics.e2e.access.e2e.test.js +42 -0
  356. package/dist/test/e2e/api/client/metrics.e2e.access.e2e.test.js.map +1 -0
  357. package/dist/test/e2e/api/client/metrics.e2e.test.js +14 -13
  358. package/dist/test/e2e/api/client/metrics.e2e.test.js.map +1 -1
  359. package/dist/test/e2e/api/client/metricsV2.e2e.test.d.ts +1 -0
  360. package/dist/test/e2e/api/client/metricsV2.e2e.test.js +95 -0
  361. package/dist/test/e2e/api/client/metricsV2.e2e.test.js.map +1 -0
  362. package/dist/test/e2e/api/client/register.e2e.test.js +18 -14
  363. package/dist/test/e2e/api/client/register.e2e.test.js.map +1 -1
  364. package/dist/test/e2e/helpers/database-config.d.ts +1 -1
  365. package/dist/test/e2e/helpers/database-config.js +12 -8
  366. package/dist/test/e2e/helpers/database-config.js.map +1 -1
  367. package/dist/test/e2e/helpers/database-init.d.ts +7 -1
  368. package/dist/test/e2e/helpers/database-init.js +8 -7
  369. package/dist/test/e2e/helpers/database-init.js.map +1 -1
  370. package/dist/test/e2e/helpers/database.json +5 -2
  371. package/dist/test/e2e/helpers/test-helper.d.ts +1 -1
  372. package/dist/test/e2e/helpers/test-helper.js +4 -5
  373. package/dist/test/e2e/helpers/test-helper.js.map +1 -1
  374. package/dist/test/e2e/services/api-token-service.e2e.test.js +28 -15
  375. package/dist/test/e2e/services/api-token-service.e2e.test.js.map +1 -1
  376. package/dist/test/e2e/services/environment-service.test.js +36 -38
  377. package/dist/test/e2e/services/environment-service.test.js.map +1 -1
  378. package/dist/test/e2e/services/feature-toggle-service-v2.e2e.test.js +17 -11
  379. package/dist/test/e2e/services/feature-toggle-service-v2.e2e.test.js.map +1 -1
  380. package/dist/test/e2e/services/project-health-service.e2e.test.js +10 -10
  381. package/dist/test/e2e/services/project-health-service.e2e.test.js.map +1 -1
  382. package/dist/test/e2e/services/project-service.e2e.test.js +25 -2
  383. package/dist/test/e2e/services/project-service.e2e.test.js.map +1 -1
  384. package/dist/test/e2e/stores/client-metrics-store-v2.e2e.test.d.ts +1 -0
  385. package/dist/test/e2e/stores/client-metrics-store-v2.e2e.test.js +338 -0
  386. package/dist/test/e2e/stores/client-metrics-store-v2.e2e.test.js.map +1 -0
  387. package/dist/test/e2e/stores/feature-tag-store.e2e.test.js +3 -3
  388. package/dist/test/e2e/stores/feature-tag-store.e2e.test.js.map +1 -1
  389. package/dist/test/e2e/stores/project-store.e2e.test.js +4 -1
  390. package/dist/test/e2e/stores/project-store.e2e.test.js.map +1 -1
  391. package/dist/test/e2e/stores/user-feedback-store.e2e.test.js +1 -1
  392. package/dist/test/e2e/stores/user-feedback-store.e2e.test.js.map +1 -1
  393. package/dist/test/fixtures/fake-api-token-store.d.ts +2 -1
  394. package/dist/test/fixtures/fake-api-token-store.js.map +1 -1
  395. package/dist/test/fixtures/fake-client-metrics-store-v2.d.ts +20 -0
  396. package/dist/test/fixtures/fake-client-metrics-store-v2.js +52 -0
  397. package/dist/test/fixtures/fake-client-metrics-store-v2.js.map +1 -0
  398. package/dist/test/fixtures/fake-environment-store.d.ts +5 -3
  399. package/dist/test/fixtures/fake-environment-store.js +22 -15
  400. package/dist/test/fixtures/fake-environment-store.js.map +1 -1
  401. package/dist/test/fixtures/fake-event-store.d.ts +1 -0
  402. package/dist/test/fixtures/fake-event-store.js +3 -0
  403. package/dist/test/fixtures/fake-event-store.js.map +1 -1
  404. package/dist/test/fixtures/fake-feature-environment-store.d.ts +8 -5
  405. package/dist/test/fixtures/fake-feature-environment-store.js +38 -10
  406. package/dist/test/fixtures/fake-feature-environment-store.js.map +1 -1
  407. package/dist/test/fixtures/fake-feature-strategies-store.d.ts +7 -13
  408. package/dist/test/fixtures/fake-feature-strategies-store.js +13 -50
  409. package/dist/test/fixtures/fake-feature-strategies-store.js.map +1 -1
  410. package/dist/test/fixtures/fake-feature-toggle-client-store.d.ts +9 -0
  411. package/dist/test/fixtures/fake-feature-toggle-client-store.js +50 -0
  412. package/dist/test/fixtures/fake-feature-toggle-client-store.js.map +1 -0
  413. package/dist/test/fixtures/fake-feature-toggle-store.d.ts +7 -9
  414. package/dist/test/fixtures/fake-feature-toggle-store.js +7 -14
  415. package/dist/test/fixtures/fake-feature-toggle-store.js.map +1 -1
  416. package/dist/test/fixtures/fake-project-store.d.ts +1 -2
  417. package/dist/test/fixtures/fake-project-store.js +0 -7
  418. package/dist/test/fixtures/fake-project-store.js.map +1 -1
  419. package/dist/test/fixtures/permissions.d.ts +3 -3
  420. package/dist/test/fixtures/permissions.js +5 -4
  421. package/dist/test/fixtures/permissions.js.map +1 -1
  422. package/dist/test/fixtures/store.js +4 -0
  423. package/dist/test/fixtures/store.js.map +1 -1
  424. package/package.json +52 -45
  425. package/dist/lib/extract-user.d.ts +0 -2
  426. package/dist/lib/extract-user.js +0 -6
  427. package/dist/lib/extract-user.js.map +0 -1
  428. package/dist/test/e2e/api/admin/boostrap.test.js.map +0 -1
  429. package/dist/test/e2e/api/admin/project/feature.strategy.e2e.test.js +0 -516
  430. package/dist/test/e2e/api/admin/project/feature.strategy.e2e.test.js.map +0 -1
  431. package/docs/api/oas/swagger-ui-bundle.js +0 -3
  432. package/docs/api/oas/swagger-ui-bundle.js.map +0 -1
  433. package/docs/api/oas/swagger-ui-es-bundle-core.js +0 -3
  434. package/docs/api/oas/swagger-ui-es-bundle-core.js.map +0 -1
  435. package/docs/api/oas/swagger-ui-es-bundle.js +0 -3
  436. package/docs/api/oas/swagger-ui-es-bundle.js.map +0 -1
  437. package/docs/api/oas/swagger-ui-standalone-preset.js +0 -3
  438. package/docs/api/oas/swagger-ui-standalone-preset.js.map +0 -1
  439. package/docs/api/oas/swagger-ui.css +0 -8906
  440. package/docs/api/oas/swagger-ui.css.map +0 -1
  441. package/docs/api/oas/swagger-ui.js +0 -3
  442. package/docs/api/oas/swagger-ui.js.map +0 -1
  443. package/docs/api/oas/swagger.json +0 -1479
@@ -0,0 +1,1267 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const database_init_1 = __importDefault(require("../../../helpers/database-init"));
7
+ const test_helper_1 = require("../../../helpers/test-helper");
8
+ const no_logger_1 = __importDefault(require("../../../../fixtures/no-logger"));
9
+ const constants_1 = require("../../../../../lib/util/constants");
10
+ const events_1 = require("../../../../../lib/types/events");
11
+ let app;
12
+ let db;
13
+ const sortOrderFirst = 0;
14
+ const sortOrderSecond = 10;
15
+ const sortOrderDefault = 9999;
16
+ beforeAll(async () => {
17
+ db = await database_init_1.default('feature_strategy_api_serial', no_logger_1.default);
18
+ app = await test_helper_1.setupApp(db.stores);
19
+ });
20
+ afterEach(async () => {
21
+ const all = await db.stores.projectStore.getEnvironmentsForProject('default');
22
+ await Promise.all(all
23
+ .filter((env) => env !== constants_1.DEFAULT_ENV)
24
+ .map(async (env) => db.stores.projectStore.deleteEnvironmentForProject('default', env)));
25
+ });
26
+ afterAll(async () => {
27
+ await app.destroy();
28
+ await db.destroy();
29
+ });
30
+ async function addStrategies(featureName, envName) {
31
+ await app.request
32
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies`)
33
+ .send({
34
+ name: 'default',
35
+ parameters: {
36
+ userId: 'string',
37
+ },
38
+ })
39
+ .expect(200);
40
+ await app.request
41
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies`)
42
+ .send({
43
+ name: 'default',
44
+ parameters: {
45
+ userId: 'string',
46
+ },
47
+ sortOrder: sortOrderFirst,
48
+ })
49
+ .expect(200);
50
+ await app.request
51
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies`)
52
+ .send({
53
+ name: 'default',
54
+ parameters: {
55
+ userId: 'string',
56
+ },
57
+ sortOrder: sortOrderSecond,
58
+ })
59
+ .expect(200);
60
+ }
61
+ test('Trying to add a strategy configuration to environment not connected to toggle should fail', async () => {
62
+ await app.request
63
+ .post('/api/admin/features')
64
+ .send({
65
+ name: 'com.test.feature',
66
+ enabled: false,
67
+ strategies: [{ name: 'default' }],
68
+ })
69
+ .set('Content-Type', 'application/json')
70
+ .expect(201)
71
+ .expect((res) => {
72
+ expect(res.body.name).toBe('com.test.feature');
73
+ expect(res.body.createdAt).toBeTruthy();
74
+ });
75
+ return app.request
76
+ .post('/api/admin/projects/default/features/com.test.feature/environments/dev/strategies')
77
+ .send({
78
+ name: 'default',
79
+ parameters: {
80
+ userId: '14',
81
+ },
82
+ })
83
+ .expect(400)
84
+ .expect((r) => {
85
+ expect(r.body.details[0].message).toBe('You have not added the current environment to the project');
86
+ });
87
+ });
88
+ test('Can get project overview', async () => {
89
+ await app.request
90
+ .post('/api/admin/features')
91
+ .send({
92
+ name: 'project-overview',
93
+ enabled: false,
94
+ strategies: [{ name: 'default' }],
95
+ })
96
+ .set('Content-Type', 'application/json')
97
+ .expect(201)
98
+ .expect((res) => {
99
+ expect(res.body.name).toBe('project-overview');
100
+ expect(res.body.createdAt).toBeTruthy();
101
+ });
102
+ await app.request
103
+ .get('/api/admin/projects/default')
104
+ .expect(200)
105
+ .expect((r) => {
106
+ expect(r.body.name).toBe('Default');
107
+ expect(r.body.features).toHaveLength(2);
108
+ expect(r.body.members).toBe(0);
109
+ });
110
+ });
111
+ test('Can get features for project', async () => {
112
+ await app.request
113
+ .post('/api/admin/projects/default/features')
114
+ .send({
115
+ name: 'features-for-project',
116
+ })
117
+ .set('Content-Type', 'application/json')
118
+ .expect(201)
119
+ .expect((res) => {
120
+ expect(res.body.name).toBe('features-for-project');
121
+ expect(res.body.createdAt).toBeTruthy();
122
+ });
123
+ await app.request
124
+ .get('/api/admin/projects/default/features')
125
+ .expect(200)
126
+ .expect((res) => {
127
+ expect(res.body.version).toBeTruthy();
128
+ expect(res.body.features.some((feature) => feature.name === 'features-for-project')).toBeTruthy();
129
+ });
130
+ });
131
+ test('Project overview includes environment connected to feature', async () => {
132
+ await app.request
133
+ .post('/api/admin/features')
134
+ .send({
135
+ name: 'com.test.environment',
136
+ enabled: false,
137
+ strategies: [{ name: 'default' }],
138
+ })
139
+ .set('Content-Type', 'application/json')
140
+ .expect(201)
141
+ .expect((res) => {
142
+ expect(res.body.name).toBe('com.test.environment');
143
+ expect(res.body.createdAt).toBeTruthy();
144
+ });
145
+ await db.stores.environmentStore.create({
146
+ name: 'project-overview',
147
+ type: 'production',
148
+ });
149
+ await app.request
150
+ .post('/api/admin/projects/default/environments')
151
+ .send({ environment: 'project-overview' })
152
+ .expect(200);
153
+ return app.request
154
+ .get('/api/admin/projects/default')
155
+ .expect(200)
156
+ .expect((r) => {
157
+ expect(r.body.features[0].environments[0].name).toBe(constants_1.DEFAULT_ENV);
158
+ expect(r.body.features[0].environments[1].name).toBe('project-overview');
159
+ });
160
+ });
161
+ test('Disconnecting environment from project, removes environment from features in project overview', async () => {
162
+ await app.request
163
+ .post('/api/admin/features')
164
+ .send({
165
+ name: 'com.test.disconnect.environment',
166
+ enabled: false,
167
+ strategies: [{ name: 'default' }],
168
+ })
169
+ .set('Content-Type', 'application/json')
170
+ .expect(201)
171
+ .expect((res) => {
172
+ expect(res.body.name).toBe('com.test.disconnect.environment');
173
+ expect(res.body.createdAt).toBeTruthy();
174
+ });
175
+ await db.stores.environmentStore.create({
176
+ name: 'dis-project-overview',
177
+ type: 'production',
178
+ });
179
+ await app.request
180
+ .post('/api/admin/projects/default/environments')
181
+ .send({ environment: 'dis-project-overview' })
182
+ .expect(200);
183
+ await app.request
184
+ .delete('/api/admin/projects/default/environments/dis-project-overview')
185
+ .expect(200);
186
+ return app.request
187
+ .get('/api/admin/projects/default')
188
+ .expect(200)
189
+ .expect((r) => {
190
+ expect(r.body.features.some((e) => e.environment === 'dis-project-overview')).toBeFalsy();
191
+ });
192
+ });
193
+ test('Can enable/disable environment for feature with strategies', async () => {
194
+ const envName = 'enable-feature-environment';
195
+ const featureName = 'com.test.enable.environment';
196
+ // Create environment
197
+ await db.stores.environmentStore.create({
198
+ name: envName,
199
+ type: 'production',
200
+ });
201
+ // Connect environment to project
202
+ await app.request
203
+ .post('/api/admin/projects/default/environments')
204
+ .send({
205
+ environment: envName,
206
+ })
207
+ .expect(200);
208
+ // Create feature
209
+ await app.request
210
+ .post('/api/admin/projects/default/features')
211
+ .send({
212
+ name: featureName,
213
+ })
214
+ .set('Content-Type', 'application/json')
215
+ .expect(201)
216
+ .expect((res) => {
217
+ expect(res.body.name).toBe(featureName);
218
+ expect(res.body.createdAt).toBeTruthy();
219
+ });
220
+ // Add strategy to it
221
+ await app.request
222
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies`)
223
+ .send({
224
+ name: 'default',
225
+ parameters: {
226
+ userId: 'string',
227
+ },
228
+ })
229
+ .expect(200);
230
+ await app.request
231
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${envName}/on`)
232
+ .set('Content-Type', 'application/json')
233
+ .expect(200);
234
+ await app.request
235
+ .get(`/api/admin/projects/default/features/${featureName}`)
236
+ .expect(200)
237
+ .expect('Content-Type', /json/)
238
+ .expect((res) => {
239
+ const enabledFeatureEnv = res.body.environments.find((e) => e.name === 'enable-feature-environment');
240
+ expect(enabledFeatureEnv).toBeTruthy();
241
+ expect(enabledFeatureEnv.enabled).toBe(true);
242
+ });
243
+ await app.request
244
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${envName}/off`)
245
+ .send({})
246
+ .expect(200);
247
+ await app.request
248
+ .get(`/api/admin/projects/default/features/${featureName}`)
249
+ .expect(200)
250
+ .expect('Content-Type', /json/)
251
+ .expect((res) => {
252
+ const disabledFeatureEnv = res.body.environments.find((e) => e.name === 'enable-feature-environment');
253
+ expect(disabledFeatureEnv).toBeTruthy();
254
+ expect(disabledFeatureEnv.enabled).toBe(false);
255
+ });
256
+ });
257
+ test("Trying to get a project that doesn't exist yields 404", async () => {
258
+ await app.request.get('/api/admin/projects/nonexisting').expect(404);
259
+ });
260
+ test('Trying to get features for non-existing project also yields 404', async () => {
261
+ await app.request
262
+ .get('/api/admin/projects/nonexisting/features')
263
+ .expect(200)
264
+ .expect((res) => {
265
+ expect(res.body.features).toHaveLength(0);
266
+ });
267
+ });
268
+ test('Can use new project feature toggle endpoint to create feature toggle without strategies', async () => {
269
+ await app.request
270
+ .post('/api/admin/projects/default/features')
271
+ .send({
272
+ name: 'new.toggle.without.strategy',
273
+ })
274
+ .expect(201)
275
+ .expect((res) => {
276
+ expect(res.body.project).toBe('default');
277
+ });
278
+ });
279
+ test('Can create feature toggle without strategies', async () => {
280
+ const name = 'new.toggle.without.strategy.2';
281
+ await app.request
282
+ .post('/api/admin/projects/default/features')
283
+ .send({ name });
284
+ const { body: toggle } = await app.request.get(`/api/admin/projects/default/features/${name}`);
285
+ expect(toggle.environments).toHaveLength(1);
286
+ expect(toggle.environments[0].strategies).toHaveLength(0);
287
+ });
288
+ test('Still validates feature toggle input when creating', async () => {
289
+ await app.request
290
+ .post('/api/admin/projects/default/features')
291
+ .send({
292
+ name: 'Some invalid name',
293
+ })
294
+ .expect(400);
295
+ });
296
+ test('Trying to create toggle that already exists yield 409 error', async () => {
297
+ await app.request
298
+ .post('/api/admin/projects/default/features')
299
+ .send({
300
+ name: 'already.exists.test',
301
+ })
302
+ .expect(201)
303
+ .expect((res) => {
304
+ expect(res.body.project).toBe('default');
305
+ });
306
+ await app.request
307
+ .post('/api/admin/projects/default/features')
308
+ .send({
309
+ name: 'already.exists.test',
310
+ })
311
+ .expect(409);
312
+ });
313
+ test('Trying to create toggle under project that does not exist should fail', async () => {
314
+ await app.request
315
+ .post('/api/admin/projects/non-existing-secondary/features')
316
+ .send({
317
+ name: 'project.does.not.exist',
318
+ })
319
+ .expect(404);
320
+ });
321
+ test('Can get environment info for feature toggle', async () => {
322
+ const envName = 'environment-info';
323
+ // Create environment
324
+ await db.stores.environmentStore.create({
325
+ name: envName,
326
+ type: 'production',
327
+ });
328
+ // Connect environment to project
329
+ await app.request
330
+ .post('/api/admin/projects/default/environments')
331
+ .send({
332
+ environment: envName,
333
+ })
334
+ .expect(200);
335
+ await app.request
336
+ .post('/api/admin/projects/default/features')
337
+ .send({ name: 'environment.info' })
338
+ .expect(201);
339
+ await app.request
340
+ .get(`/api/admin/projects/default/features/environment.info/environments/${envName}`)
341
+ .expect(200)
342
+ .expect((res) => {
343
+ expect(res.body.enabled).toBe(false);
344
+ expect(res.body.environment).toBe(envName);
345
+ expect(res.body.strategies).toHaveLength(0);
346
+ });
347
+ });
348
+ test('Getting environment info for environment that does not exist yields 404', async () => {
349
+ await app.request
350
+ .post('/api/admin/projects/default/features')
351
+ .send({ name: 'non.existing.env' })
352
+ .expect(201);
353
+ await app.request
354
+ .get('/api/admin/projects/default/features/non.existing.env/environments/non.existing.environment')
355
+ .expect(404);
356
+ });
357
+ test('Trying to toggle environment that does not exist yields 404', async () => {
358
+ await app.request
359
+ .post('/api/admin/projects/default/features')
360
+ .send({ name: 'toggle.env' })
361
+ .expect(201);
362
+ await app.request
363
+ .post('/api/admin/projects/default/features/toggle.env/environments/does-not-exist/on')
364
+ .send({})
365
+ .expect(404);
366
+ await app.request
367
+ .post('/api/admin/projects/default/features/toggle.env/environments/does-not-exist/off')
368
+ .send({})
369
+ .expect(404);
370
+ });
371
+ test('Getting feature that does not exist should yield 404', async () => {
372
+ await app.request
373
+ .get('/api/admin/projects/default/features/non.existing.feature')
374
+ .expect(404);
375
+ });
376
+ test('Should update feature toggle', async () => {
377
+ const url = '/api/admin/projects/default/features';
378
+ const name = 'new.toggle.update';
379
+ await app.request
380
+ .post(url)
381
+ .send({ name, description: 'some', type: 'release' })
382
+ .expect(201);
383
+ await app.request
384
+ .put(`${url}/${name}`)
385
+ .send({ name, description: 'updated', type: 'kill-switch' })
386
+ .expect(200);
387
+ const { body: toggle } = await app.request.get(`${url}/${name}`);
388
+ expect(toggle.name).toBe(name);
389
+ expect(toggle.description).toBe('updated');
390
+ expect(toggle.type).toBe('kill-switch');
391
+ expect(toggle.archived).toBeFalsy();
392
+ });
393
+ test('Should not change name of feature toggle', async () => {
394
+ const url = '/api/admin/projects/default/features';
395
+ const name = 'new.toggle.update.2';
396
+ await app.request
397
+ .post(url)
398
+ .send({ name, description: 'some', type: 'release' })
399
+ .expect(201);
400
+ await app.request
401
+ .put(`${url}/${name}`)
402
+ .send({ name: 'new name', description: 'updated', type: 'kill-switch' })
403
+ .expect(400);
404
+ });
405
+ test('Should not change project of feature toggle even if it is part of body', async () => {
406
+ const url = '/api/admin/projects/default/features';
407
+ const name = 'new.toggle.update.3';
408
+ await app.request
409
+ .post(url)
410
+ .send({ name, description: 'some', type: 'release' })
411
+ .expect(201);
412
+ const { body } = await app.request
413
+ .put(`${url}/${name}`)
414
+ .send({
415
+ name,
416
+ description: 'updated',
417
+ type: 'kill-switch',
418
+ project: 'new',
419
+ })
420
+ .expect(200);
421
+ expect(body.project).toBe('default');
422
+ });
423
+ test('Should patch feature toggle', async () => {
424
+ const url = '/api/admin/projects/default/features';
425
+ const name = 'new.toggle.patch';
426
+ await app.request
427
+ .post(url)
428
+ .send({ name, description: 'some', type: 'release' })
429
+ .expect(201);
430
+ await app.request
431
+ .patch(`${url}/${name}`)
432
+ .send([
433
+ { op: 'replace', path: '/description', value: 'New desc' },
434
+ { op: 'replace', path: '/type', value: 'kill-switch' },
435
+ ])
436
+ .expect(200);
437
+ const { body: toggle } = await app.request.get(`${url}/${name}`);
438
+ expect(toggle.name).toBe(name);
439
+ expect(toggle.description).toBe('New desc');
440
+ expect(toggle.type).toBe('kill-switch');
441
+ expect(toggle.archived).toBeFalsy();
442
+ const events = await db.stores.eventStore.getAll({
443
+ type: events_1.FEATURE_METADATA_UPDATED,
444
+ });
445
+ const updateForOurToggle = events.find((e) => e.data.name === name);
446
+ expect(updateForOurToggle).toBeTruthy();
447
+ expect(updateForOurToggle.data.description).toBe('New desc');
448
+ expect(updateForOurToggle.data.type).toBe('kill-switch');
449
+ });
450
+ test('Patching feature toggles to stale should trigger FEATURE_STALE_ON event', async () => {
451
+ const url = '/api/admin/projects/default/features';
452
+ const name = 'toggle.stale.on.patch';
453
+ await app.request
454
+ .post(url)
455
+ .send({ name, description: 'some', type: 'release', stale: false })
456
+ .expect(201);
457
+ await app.request
458
+ .patch(`${url}/${name}`)
459
+ .send([{ op: 'replace', path: '/stale', value: true }])
460
+ .expect(200);
461
+ const { body: toggle } = await app.request.get(`${url}/${name}`);
462
+ expect(toggle.name).toBe(name);
463
+ expect(toggle.archived).toBeFalsy();
464
+ expect(toggle.stale).toBeTruthy();
465
+ const events = await db.stores.eventStore.getAll({
466
+ type: events_1.FEATURE_STALE_ON,
467
+ });
468
+ const updateForOurToggle = events.find((e) => e.data.name === name);
469
+ expect(updateForOurToggle).toBeTruthy();
470
+ expect(updateForOurToggle.data.stale).toBe(true);
471
+ });
472
+ test('Patching feature toggles to active (turning stale to false) should trigger FEATURE_STALE_OFF event', async () => {
473
+ const url = '/api/admin/projects/default/features';
474
+ const name = 'toggle.stale.off.patch';
475
+ await app.request
476
+ .post(url)
477
+ .send({ name, description: 'some', type: 'release', stale: true })
478
+ .expect(201);
479
+ await app.request
480
+ .patch(`${url}/${name}`)
481
+ .send([{ op: 'replace', path: '/stale', value: false }])
482
+ .expect(200);
483
+ const { body: toggle } = await app.request.get(`${url}/${name}`);
484
+ expect(toggle.name).toBe(name);
485
+ expect(toggle.archived).toBeFalsy();
486
+ expect(toggle.stale).toBe(false);
487
+ const events = await db.stores.eventStore.getAll({
488
+ type: events_1.FEATURE_STALE_OFF,
489
+ });
490
+ const updateForOurToggle = events.find((e) => e.data.name === name);
491
+ expect(updateForOurToggle).toBeTruthy();
492
+ expect(updateForOurToggle.data.stale).toBe(false);
493
+ });
494
+ test('Should archive feature toggle', async () => {
495
+ const url = '/api/admin/projects/default/features';
496
+ const name = 'new.toggle.archive';
497
+ await app.request
498
+ .post(url)
499
+ .send({ name, description: 'some', type: 'release' })
500
+ .expect(201);
501
+ await app.request.delete(`${url}/${name}`);
502
+ await app.request.get(`${url}/${name}`).expect(404);
503
+ const { body } = await app.request
504
+ .get(`/api/admin/archive/features`)
505
+ .expect(200);
506
+ const toggle = body.features.find((f) => f.name === name);
507
+ expect(toggle).toBeDefined();
508
+ });
509
+ test('Can add strategy to feature toggle to a "some-env-2"', async () => {
510
+ const envName = 'some-env-2';
511
+ const featureName = 'feature.strategy.toggle';
512
+ // Create environment
513
+ await db.stores.environmentStore.create({
514
+ name: envName,
515
+ type: 'production',
516
+ });
517
+ // Connect environment to project
518
+ await app.request
519
+ .post('/api/admin/projects/default/environments')
520
+ .send({
521
+ environment: envName,
522
+ })
523
+ .expect(200);
524
+ await app.request
525
+ .post('/api/admin/projects/default/features')
526
+ .send({ name: featureName })
527
+ .expect(201);
528
+ await app.request
529
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies`)
530
+ .send({
531
+ name: 'default',
532
+ parameters: {
533
+ userId: 'string',
534
+ },
535
+ })
536
+ .expect(200);
537
+ await app.request
538
+ .get(`/api/admin/projects/default/features/${featureName}`)
539
+ .expect((res) => {
540
+ const env = res.body.environments.find((e) => e.name === envName);
541
+ expect(env.strategies).toHaveLength(1);
542
+ });
543
+ });
544
+ test('Environments are returned in sortOrder', async () => {
545
+ const sortedSecond = 'sortedSecond';
546
+ const sortedLast = 'sortedLast';
547
+ const featureName = 'feature.strategy.toggle.sortOrder';
548
+ // Create environments
549
+ await db.stores.environmentStore.create({
550
+ name: sortedLast,
551
+ type: 'production',
552
+ sortOrder: 8000,
553
+ });
554
+ await db.stores.environmentStore.create({
555
+ name: sortedSecond,
556
+ type: 'production',
557
+ sortOrder: 8,
558
+ });
559
+ // Connect environments to project
560
+ await app.request
561
+ .post('/api/admin/projects/default/environments')
562
+ .send({
563
+ environment: sortedSecond,
564
+ })
565
+ .expect(200);
566
+ await app.request
567
+ .post('/api/admin/projects/default/environments')
568
+ .send({
569
+ environment: sortedLast,
570
+ })
571
+ .expect(200);
572
+ /* Create feature toggle */
573
+ await app.request
574
+ .post('/api/admin/projects/default/features')
575
+ .send({ name: featureName })
576
+ .expect(201);
577
+ /* create strategies connected to feature toggle */
578
+ await app.request
579
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${sortedSecond}/strategies`)
580
+ .send({
581
+ name: 'default',
582
+ parameters: {
583
+ userId: 'string',
584
+ },
585
+ })
586
+ .expect(200);
587
+ await app.request
588
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${sortedLast}/strategies`)
589
+ .send({
590
+ name: 'default',
591
+ parameters: {
592
+ userId: 'string',
593
+ },
594
+ })
595
+ .expect(200);
596
+ await app.request
597
+ .get(`/api/admin/projects/default/features/${featureName}`)
598
+ .expect(200)
599
+ .expect((res) => {
600
+ expect(res.body.environments).toHaveLength(3);
601
+ expect(res.body.environments[0].name).toBe(constants_1.DEFAULT_ENV);
602
+ expect(res.body.environments[1].name).toBe(sortedSecond);
603
+ expect(res.body.environments[2].name).toBe(sortedLast);
604
+ });
605
+ });
606
+ test('Can get strategies for feature and environment', async () => {
607
+ const envName = 'get-strategy';
608
+ // Create environment
609
+ await db.stores.environmentStore.create({
610
+ name: envName,
611
+ type: 'production',
612
+ });
613
+ // Connect environment to project
614
+ await app.request
615
+ .post('/api/admin/projects/default/environments')
616
+ .send({
617
+ environment: envName,
618
+ })
619
+ .expect(200);
620
+ const featureName = 'feature.get.strategies';
621
+ await app.request
622
+ .post('/api/admin/projects/default/features')
623
+ .send({ name: featureName })
624
+ .expect(201);
625
+ await app.request
626
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies`)
627
+ .send({
628
+ name: 'default',
629
+ parameters: {
630
+ userId: 'string',
631
+ },
632
+ })
633
+ .expect(200);
634
+ await app.request
635
+ .get(`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies`)
636
+ .expect(200)
637
+ .expect((res) => {
638
+ expect(res.body).toHaveLength(1);
639
+ expect(res.body[0].parameters.userId).toBe('string');
640
+ });
641
+ });
642
+ test('Getting strategies for environment that does not exist yields 404', async () => {
643
+ const featureName = 'feature.get.strategies.for.nonexisting';
644
+ await app.request
645
+ .post('/api/admin/projects/default/features')
646
+ .send({ name: featureName })
647
+ .expect(201);
648
+ await app.request
649
+ .get(`/api/admin/projects/default/features/${featureName}/environments/should.not.exist/strategies`)
650
+ .expect(404);
651
+ });
652
+ test('Can update a strategy based on id', async () => {
653
+ const envName = 'feature.update.strategies';
654
+ // Create environment
655
+ await db.stores.environmentStore.create({
656
+ name: envName,
657
+ type: 'production',
658
+ });
659
+ // Connect environment to project
660
+ await app.request
661
+ .post('/api/admin/projects/default/environments')
662
+ .send({
663
+ environment: envName,
664
+ })
665
+ .expect(200);
666
+ const featureName = 'feature.update.strategies';
667
+ await app.request
668
+ .post('/api/admin/projects/default/features')
669
+ .send({ name: featureName })
670
+ .expect(201);
671
+ let strategy;
672
+ await app.request
673
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies`)
674
+ .send({
675
+ name: 'default',
676
+ parameters: {
677
+ userId: 'string',
678
+ },
679
+ })
680
+ .expect(200)
681
+ .expect((res) => {
682
+ strategy = res.body;
683
+ });
684
+ await app.request
685
+ .put(`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies/${strategy.id}`)
686
+ .send({ parameters: { userId: 'string', companyId: 'string' } })
687
+ .expect(200);
688
+ await app.request
689
+ .get(`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies/${strategy.id}`)
690
+ .expect(200)
691
+ .expect((res) => {
692
+ expect(res.body.parameters.companyId).toBeTruthy();
693
+ expect(res.body.parameters.userId).toBeTruthy();
694
+ });
695
+ });
696
+ test('Trying to update a non existing feature strategy should yield 404', async () => {
697
+ const envName = 'feature.non.existing.strategy';
698
+ // Create environment
699
+ await db.stores.environmentStore.create({
700
+ name: envName,
701
+ type: 'production',
702
+ });
703
+ // Connect environment to project
704
+ await app.request
705
+ .post('/api/admin/projects/default/environments')
706
+ .send({
707
+ environment: envName,
708
+ })
709
+ .expect(200);
710
+ const featureName = 'feature.non.existing.strategy';
711
+ await app.request
712
+ .post('/api/admin/projects/default/features')
713
+ .send({ name: featureName })
714
+ .expect(201);
715
+ await app.request
716
+ .put(`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies/some-non-existing-id`)
717
+ .send({ parameters: { fancyField: 'string' } })
718
+ .expect(404);
719
+ });
720
+ test('Can patch a strategy based on id', async () => {
721
+ const BASE_URI = '/api/admin/projects/default';
722
+ const envName = 'feature.patch.strategies';
723
+ const featureName = 'feature.patch.strategies';
724
+ // Create environment
725
+ await db.stores.environmentStore.create({
726
+ name: envName,
727
+ type: 'test',
728
+ });
729
+ // Connect environment to project
730
+ await app.request
731
+ .post(`${BASE_URI}/environments`)
732
+ .send({
733
+ environment: envName,
734
+ })
735
+ .expect(200);
736
+ await app.request
737
+ .post(`${BASE_URI}/features`)
738
+ .send({ name: featureName })
739
+ .expect(201);
740
+ let strategy;
741
+ await app.request
742
+ .post(`${BASE_URI}/features/${featureName}/environments/${envName}/strategies`)
743
+ .send({
744
+ name: 'flexibleRollout',
745
+ parameters: {
746
+ groupId: 'demo',
747
+ rollout: 20,
748
+ stickiness: 'default',
749
+ },
750
+ })
751
+ .expect(200)
752
+ .expect((res) => {
753
+ strategy = res.body;
754
+ });
755
+ await app.request
756
+ .patch(`${BASE_URI}/features/${featureName}/environments/${envName}/strategies/${strategy.id}`)
757
+ .send([{ op: 'replace', path: '/parameters/rollout', value: 42 }])
758
+ .expect(200);
759
+ await app.request
760
+ .get(`${BASE_URI}/features/${featureName}/environments/${envName}/strategies/${strategy.id}`)
761
+ .expect(200)
762
+ .expect((res) => {
763
+ expect(res.body.parameters.rollout).toBe(42);
764
+ });
765
+ });
766
+ test('Trying to get a non existing feature strategy should yield 404', async () => {
767
+ const envName = 'feature.non.existing.strategy.get';
768
+ // Create environment
769
+ await db.stores.environmentStore.create({
770
+ name: envName,
771
+ type: 'production',
772
+ });
773
+ // Connect environment to project
774
+ await app.request
775
+ .post('/api/admin/projects/default/environments')
776
+ .send({
777
+ environment: envName,
778
+ })
779
+ .expect(200);
780
+ const featureName = 'feature.non.existing.strategy.get';
781
+ await app.request
782
+ .post('/api/admin/projects/default/features')
783
+ .send({ name: featureName })
784
+ .expect(201);
785
+ await app.request
786
+ .get(`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies/some-non-existing-id`)
787
+ .expect(404);
788
+ });
789
+ test('Can not enable environment for feature without strategies', async () => {
790
+ const environment = 'some-env';
791
+ const featureName = 'com.test.enable.environment.disabled';
792
+ // Create environment
793
+ await db.stores.environmentStore.create({
794
+ name: environment,
795
+ type: 'test',
796
+ });
797
+ // Connect environment to project
798
+ await app.request
799
+ .post('/api/admin/projects/default/environments')
800
+ .send({ environment })
801
+ .expect(200);
802
+ // Create feature
803
+ await app.request
804
+ .post('/api/admin/projects/default/features')
805
+ .send({
806
+ name: featureName,
807
+ })
808
+ .set('Content-Type', 'application/json')
809
+ .expect(201);
810
+ await app.request
811
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${environment}/on`)
812
+ .set('Content-Type', 'application/json')
813
+ .expect(403);
814
+ await app.request
815
+ .get(`/api/admin/projects/default/features/${featureName}`)
816
+ .expect(200)
817
+ .expect('Content-Type', /json/)
818
+ .expect((res) => {
819
+ const enabledFeatureEnv = res.body.environments.find((e) => e.name === environment);
820
+ expect(enabledFeatureEnv.enabled).toBe(false);
821
+ expect(enabledFeatureEnv.type).toBe('test');
822
+ });
823
+ });
824
+ test('Deleting a strategy should include name of feature strategy was deleted from', async () => {
825
+ const environment = 'delete_strategy_env';
826
+ const featureName = 'delete_strategy_feature';
827
+ // Create environment
828
+ await db.stores.environmentStore.create({
829
+ name: environment,
830
+ type: 'test',
831
+ });
832
+ // Connect environment to project
833
+ await app.request
834
+ .post('/api/admin/projects/default/environments')
835
+ .send({ environment })
836
+ .expect(200);
837
+ // Create feature
838
+ await app.request
839
+ .post('/api/admin/projects/default/features')
840
+ .send({
841
+ name: featureName,
842
+ })
843
+ .set('Content-Type', 'application/json')
844
+ .expect(201);
845
+ let strategyId;
846
+ await app.request
847
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${environment}/strategies`)
848
+ .send({ name: 'default', constraints: [], properties: {} })
849
+ .expect(200)
850
+ .expect((res) => {
851
+ strategyId = res.body.id;
852
+ });
853
+ expect(strategyId).toBeTruthy();
854
+ // Delete strategy
855
+ await app.request
856
+ .delete(`/api/admin/projects/default/features/${featureName}/environments/${environment}/strategies/${strategyId}`)
857
+ .expect(200);
858
+ const events = await db.stores.eventStore.getAll({
859
+ type: events_1.FEATURE_STRATEGY_REMOVE,
860
+ });
861
+ expect(events).toHaveLength(1);
862
+ expect(events[0].data.featureName).toBe(featureName);
863
+ expect(events[0].environment).toBe(environment);
864
+ expect(events[0].data.id).toBe(strategyId);
865
+ });
866
+ test('Enabling environment creates a FEATURE_ENVIRONMENT_ENABLED event', async () => {
867
+ const environment = 'environment_enabled_env';
868
+ const featureName = 'com.test.enable.environment.event.sent';
869
+ // Create environment
870
+ await db.stores.environmentStore.create({
871
+ name: environment,
872
+ type: 'test',
873
+ });
874
+ // Connect environment to project
875
+ await app.request
876
+ .post('/api/admin/projects/default/environments')
877
+ .send({ environment })
878
+ .expect(200);
879
+ // Create feature
880
+ await app.request
881
+ .post('/api/admin/projects/default/features')
882
+ .send({
883
+ name: featureName,
884
+ })
885
+ .set('Content-Type', 'application/json')
886
+ .expect(201);
887
+ await app.request
888
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${environment}/strategies`)
889
+ .send({ name: 'default', constraints: [], properties: {} })
890
+ .expect(200);
891
+ await app.request
892
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${environment}/on`)
893
+ .set('Content-Type', 'application/json')
894
+ .expect(200);
895
+ const events = await db.stores.eventStore.getAll({
896
+ type: events_1.FEATURE_ENVIRONMENT_ENABLED,
897
+ });
898
+ const enabledEvents = events.filter((e) => e.data.name === featureName);
899
+ expect(enabledEvents).toHaveLength(1);
900
+ });
901
+ test('Disabling environment creates a FEATURE_ENVIRONMENT_DISABLED event', async () => {
902
+ const environment = 'environment_disabled_env';
903
+ const featureName = 'com.test.enable.environment_disabled.sent';
904
+ // Create environment
905
+ await db.stores.environmentStore.create({
906
+ name: environment,
907
+ type: 'test',
908
+ });
909
+ // Connect environment to project
910
+ await app.request
911
+ .post('/api/admin/projects/default/environments')
912
+ .send({ environment })
913
+ .expect(200);
914
+ // Create feature
915
+ await app.request
916
+ .post('/api/admin/projects/default/features')
917
+ .send({
918
+ name: featureName,
919
+ })
920
+ .set('Content-Type', 'application/json')
921
+ .expect(201);
922
+ await app.request
923
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${environment}/strategies`)
924
+ .send({ name: 'default', constraints: [], properties: {} })
925
+ .expect(200);
926
+ await app.request
927
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${environment}/off`)
928
+ .set('Content-Type', 'application/json')
929
+ .expect(200);
930
+ const events = await db.stores.eventStore.getAll({
931
+ type: events_1.FEATURE_ENVIRONMENT_DISABLED,
932
+ });
933
+ const ourFeatureEvent = events.find((e) => e.data.name === featureName);
934
+ expect(ourFeatureEvent).toBeTruthy();
935
+ });
936
+ test('Can delete strategy from feature toggle', async () => {
937
+ const envName = 'del-strategy';
938
+ const featureName = 'feature.strategy.toggle.delete.strategy';
939
+ // Create environment
940
+ await db.stores.environmentStore.create({
941
+ name: envName,
942
+ type: 'test',
943
+ });
944
+ // Connect environment to project
945
+ await app.request
946
+ .post('/api/admin/projects/default/environments')
947
+ .send({
948
+ environment: envName,
949
+ })
950
+ .expect(200);
951
+ await app.request
952
+ .post('/api/admin/projects/default/features')
953
+ .send({ name: featureName })
954
+ .expect(201);
955
+ await app.request
956
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies`)
957
+ .send({
958
+ name: 'default',
959
+ parameters: {
960
+ userId: 'string',
961
+ },
962
+ })
963
+ .expect(200);
964
+ const { body } = await app.request.get(`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies`);
965
+ const strategies = body;
966
+ const strategyId = strategies[0].id;
967
+ await app.request
968
+ .delete(`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies/${strategyId}`)
969
+ .expect(200);
970
+ });
971
+ test('List of strategies should respect sortOrder', async () => {
972
+ const envName = 'sortOrderdel-strategy';
973
+ const featureName = 'feature.sort.order.one';
974
+ // Create environment
975
+ await db.stores.environmentStore.create({
976
+ name: envName,
977
+ type: 'test',
978
+ });
979
+ // Connect environment to project
980
+ await app.request
981
+ .post('/api/admin/projects/default/environments')
982
+ .send({
983
+ environment: envName,
984
+ })
985
+ .expect(200);
986
+ await app.request
987
+ .post('/api/admin/projects/default/features')
988
+ .send({ name: featureName })
989
+ .expect(201);
990
+ await addStrategies(featureName, envName);
991
+ const { body } = await app.request.get(`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies`);
992
+ const strategies = body;
993
+ expect(strategies[0].sortOrder).toBe(sortOrderFirst);
994
+ expect(strategies[1].sortOrder).toBe(sortOrderSecond);
995
+ expect(strategies[2].sortOrder).toBe(sortOrderDefault);
996
+ });
997
+ test('Feature strategies list should respect strategy sortorders for each environment', async () => {
998
+ const envName = 'sort-order-within-environment-one';
999
+ const secondEnv = 'sort-order-within-environment-two';
1000
+ const featureName = 'feature.sort.order.environment.list';
1001
+ // Create environment
1002
+ await db.stores.environmentStore.create({
1003
+ name: envName,
1004
+ type: 'test',
1005
+ });
1006
+ await db.stores.environmentStore.create({
1007
+ name: secondEnv,
1008
+ type: 'test',
1009
+ });
1010
+ // Connect environment to project
1011
+ await app.request
1012
+ .post('/api/admin/projects/default/environments')
1013
+ .send({
1014
+ environment: envName,
1015
+ })
1016
+ .expect(200);
1017
+ await app.request
1018
+ .post('/api/admin/projects/default/environments')
1019
+ .send({
1020
+ environment: secondEnv,
1021
+ })
1022
+ .expect(200);
1023
+ await app.request
1024
+ .post('/api/admin/projects/default/features')
1025
+ .send({ name: featureName })
1026
+ .expect(201);
1027
+ await addStrategies(featureName, envName);
1028
+ await addStrategies(featureName, secondEnv);
1029
+ const response = await app.request.get(`/api/admin/projects/default/features/${featureName}`);
1030
+ const { body } = response;
1031
+ let { strategies } = body.environments.find((e) => e.name === envName);
1032
+ expect(strategies[0].sortOrder).toBe(sortOrderFirst);
1033
+ expect(strategies[1].sortOrder).toBe(sortOrderSecond);
1034
+ expect(strategies[2].sortOrder).toBe(sortOrderDefault);
1035
+ strategies = body.environments.find((e) => e.name === secondEnv).strategies;
1036
+ expect(strategies[0].sortOrder).toBe(sortOrderFirst);
1037
+ expect(strategies[1].sortOrder).toBe(sortOrderSecond);
1038
+ expect(strategies[2].sortOrder).toBe(sortOrderDefault);
1039
+ });
1040
+ test('Deleting last strategy for feature environment should disable that environment', async () => {
1041
+ const envName = 'last_strategy_delete_env';
1042
+ const featureName = 'last_strategy_delete_feature';
1043
+ // Create environment
1044
+ await db.stores.environmentStore.create({
1045
+ name: envName,
1046
+ type: 'test',
1047
+ });
1048
+ // Connect environment to project
1049
+ await app.request
1050
+ .post('/api/admin/projects/default/environments')
1051
+ .send({
1052
+ environment: envName,
1053
+ })
1054
+ .expect(200);
1055
+ await app.request
1056
+ .post('/api/admin/projects/default/features')
1057
+ .send({ name: featureName })
1058
+ .expect(201);
1059
+ let strategyId;
1060
+ await app.request
1061
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies`)
1062
+ .send({
1063
+ name: 'default',
1064
+ parameters: {
1065
+ userId: 'string',
1066
+ },
1067
+ })
1068
+ .expect(200)
1069
+ .expect((res) => {
1070
+ strategyId = res.body.id;
1071
+ });
1072
+ // Enable feature_environment
1073
+ await app.request
1074
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${envName}/on`)
1075
+ .send({})
1076
+ .expect(200);
1077
+ await app.request
1078
+ .get(`/api/admin/projects/default/features/${featureName}/environments/${envName}`)
1079
+ .expect(200)
1080
+ .expect((res) => {
1081
+ expect(res.body.enabled).toBeTruthy();
1082
+ });
1083
+ // Delete last strategy, this should also disable the environment
1084
+ await app.request.delete(`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies/${strategyId}`);
1085
+ await app.request
1086
+ .get(`/api/admin/projects/default/features/${featureName}/environments/${envName}`)
1087
+ .expect(200)
1088
+ .expect((res) => {
1089
+ expect(res.body.enabled).toBeFalsy();
1090
+ });
1091
+ });
1092
+ test('Deleting strategy for feature environment should not disable that environment as long as there are other strategies', async () => {
1093
+ const envName = 'any_strategy_delete_env';
1094
+ const featureName = 'any_strategy_delete_feature';
1095
+ // Create environment
1096
+ await db.stores.environmentStore.create({
1097
+ name: envName,
1098
+ type: 'test',
1099
+ });
1100
+ // Connect environment to project
1101
+ await app.request
1102
+ .post('/api/admin/projects/default/environments')
1103
+ .send({
1104
+ environment: envName,
1105
+ })
1106
+ .expect(200);
1107
+ await app.request
1108
+ .post('/api/admin/projects/default/features')
1109
+ .send({ name: featureName })
1110
+ .expect(201);
1111
+ let strategyId;
1112
+ await app.request
1113
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies`)
1114
+ .send({
1115
+ name: 'default',
1116
+ parameters: {
1117
+ userId: 'string',
1118
+ },
1119
+ })
1120
+ .expect(200)
1121
+ .expect((res) => {
1122
+ strategyId = res.body.id;
1123
+ });
1124
+ await app.request
1125
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies`)
1126
+ .send({
1127
+ name: 'default',
1128
+ parameters: {
1129
+ customerId: 'string',
1130
+ },
1131
+ })
1132
+ .expect(200);
1133
+ // Enable feature_environment
1134
+ await app.request
1135
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${envName}/on`)
1136
+ .send({})
1137
+ .expect(200);
1138
+ await app.request
1139
+ .get(`/api/admin/projects/default/features/${featureName}/environments/${envName}`)
1140
+ .expect(200)
1141
+ .expect((res) => {
1142
+ expect(res.body.enabled).toBeTruthy();
1143
+ });
1144
+ // Delete a strategy, this should also disable the environment
1145
+ await app.request.delete(`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies/${strategyId}`);
1146
+ await app.request
1147
+ .get(`/api/admin/projects/default/features/${featureName}/environments/${envName}`)
1148
+ .expect(200)
1149
+ .expect((res) => {
1150
+ expect(res.body.enabled).toBeTruthy();
1151
+ });
1152
+ });
1153
+ test('should clone feature toggle without strategies', async () => {
1154
+ const envName = 'some-env-3';
1155
+ const featureName = 'feature.toggle.base';
1156
+ const cloneName = 'feature.toggle.clone';
1157
+ const type = 'eExperiment';
1158
+ const description = 'Lorem ipsum...';
1159
+ // Create environment
1160
+ await db.stores.environmentStore.create({
1161
+ name: envName,
1162
+ type: 'production',
1163
+ });
1164
+ // Connect environment to project
1165
+ await app.request
1166
+ .post('/api/admin/projects/default/environments')
1167
+ .send({
1168
+ environment: envName,
1169
+ })
1170
+ .expect(200);
1171
+ await app.request
1172
+ .post('/api/admin/projects/default/features')
1173
+ .send({ name: featureName, description, type })
1174
+ .expect(201);
1175
+ await app.request
1176
+ .post(`/api/admin/projects/default/features/${featureName}/clone`)
1177
+ .send({ name: cloneName, replaceGroupId: false })
1178
+ .expect(201);
1179
+ await app.request
1180
+ .get(`/api/admin/projects/default/features/${cloneName}`)
1181
+ .expect(200)
1182
+ .expect((res) => {
1183
+ expect(res.body.name).toBe(cloneName);
1184
+ expect(res.body.type).toBe(type);
1185
+ expect(res.body.project).toBe('default');
1186
+ expect(res.body.description).toBe(description);
1187
+ });
1188
+ });
1189
+ test('should clone feature toggle WITH strategies', async () => {
1190
+ const envName = 'some-env-4';
1191
+ const featureName = 'feature.toggle.base.2';
1192
+ const cloneName = 'feature.toggle.clone.2';
1193
+ const type = 'eExperiment';
1194
+ const description = 'Lorem ipsum...';
1195
+ // Create environment
1196
+ await db.stores.environmentStore.create({
1197
+ name: envName,
1198
+ type: 'production',
1199
+ });
1200
+ // Connect environment to project
1201
+ await app.request
1202
+ .post('/api/admin/projects/default/environments')
1203
+ .send({
1204
+ environment: envName,
1205
+ })
1206
+ .expect(200);
1207
+ await app.request
1208
+ .post('/api/admin/projects/default/features')
1209
+ .send({ name: featureName, description, type })
1210
+ .expect(201);
1211
+ await app.request
1212
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies`)
1213
+ .send({
1214
+ name: 'flexibleRollout',
1215
+ parameters: {
1216
+ groupId: featureName,
1217
+ },
1218
+ })
1219
+ .expect(200);
1220
+ await app.request
1221
+ .post(`/api/admin/projects/default/features/${featureName}/clone`)
1222
+ .send({ name: cloneName })
1223
+ .expect(201);
1224
+ await app.request
1225
+ .get(`/api/admin/projects/default/features/${cloneName}`)
1226
+ .expect(200)
1227
+ .expect((res) => {
1228
+ expect(res.body.name).toBe(cloneName);
1229
+ expect(res.body.type).toBe(type);
1230
+ expect(res.body.project).toBe('default');
1231
+ expect(res.body.description).toBe(description);
1232
+ const env = res.body.environments.find((e) => e.name === envName);
1233
+ expect(env.strategies).toHaveLength(1);
1234
+ expect(env.strategies[0].parameters.groupId).toBe(cloneName);
1235
+ });
1236
+ });
1237
+ test('should clone feature toggle without replacing groupId', async () => {
1238
+ const envName = 'default';
1239
+ const featureName = 'feature.toggle.base.3';
1240
+ const cloneName = 'feature.toggle.clone.3';
1241
+ await app.request
1242
+ .post('/api/admin/projects/default/features')
1243
+ .send({ name: featureName })
1244
+ .expect(201);
1245
+ await app.request
1246
+ .post(`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies`)
1247
+ .send({
1248
+ name: 'flexibleRollout',
1249
+ parameters: {
1250
+ groupId: featureName,
1251
+ },
1252
+ })
1253
+ .expect(200);
1254
+ await app.request
1255
+ .post(`/api/admin/projects/default/features/${featureName}/clone`)
1256
+ .send({ name: cloneName, replaceGroupId: false })
1257
+ .expect(201);
1258
+ await app.request
1259
+ .get(`/api/admin/projects/default/features/${cloneName}`)
1260
+ .expect(200)
1261
+ .expect((res) => {
1262
+ const env = res.body.environments.find((e) => e.name === envName);
1263
+ expect(env.strategies).toHaveLength(1);
1264
+ expect(env.strategies[0].parameters.groupId).toBe(featureName);
1265
+ });
1266
+ });
1267
+ //# sourceMappingURL=features.e2e.test.js.map