@snowplow/react-native-tracker 1.3.0 → 2.0.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 (240) hide show
  1. package/.editorconfig +15 -0
  2. package/.eslintignore +6 -0
  3. package/.gitattributes +3 -0
  4. package/.github/ISSUE_TEMPLATE/bug_report.md +29 -0
  5. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  6. package/.github/actions/setup/action.yml +28 -0
  7. package/.github/workflows/build.yml +150 -0
  8. package/.github/workflows/deploy.yml +98 -0
  9. package/.github/workflows/e2e-android.yml +121 -0
  10. package/.github/workflows/e2e-ios.yml +90 -0
  11. package/.github/workflows/snyk.yml +21 -0
  12. package/.gitignore +70 -0
  13. package/.npmignore +60 -0
  14. package/.nvmrc +1 -0
  15. package/.watchmanconfig +1 -0
  16. package/.yarnrc +3 -0
  17. package/CHANGELOG +166 -0
  18. package/CONTRIBUTING.md +80 -0
  19. package/LICENSE +1 -1
  20. package/README.md +24 -111
  21. package/android/build.gradle +93 -37
  22. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  23. package/android/gradle/wrapper/gradle-wrapper.properties +1 -2
  24. package/android/gradle.properties +5 -2
  25. package/android/gradlew +172 -110
  26. package/android/gradlew.bat +24 -19
  27. package/android/src/main/AndroidManifest.xml +1 -3
  28. package/android/src/main/AndroidManifestNew.xml +2 -0
  29. package/android/src/main/java/com/snowplow/reactnativetracker/ReactNativeTrackerModule.kt +704 -0
  30. package/android/src/main/java/com/snowplow/reactnativetracker/ReactNativeTrackerPackage.kt +17 -0
  31. package/android/src/main/java/com/snowplow/reactnativetracker/util/ConfigUtil.kt +271 -0
  32. package/android/src/main/java/com/snowplow/reactnativetracker/util/EventUtil.kt +213 -0
  33. package/android/src/main/java/com/snowplow/reactnativetracker/util/TrackerVersion.kt +5 -0
  34. package/babel.config.js +3 -0
  35. package/example/.watchmanconfig +1 -0
  36. package/example/Gemfile +6 -0
  37. package/example/android/app/build.gradle +129 -0
  38. package/example/android/app/debug.keystore +0 -0
  39. package/example/android/app/proguard-rules.pro +10 -0
  40. package/example/android/app/src/androidTest/java/com/reactnativetrackerexample/DetoxTest.java +36 -0
  41. package/example/android/app/src/androidTest/java/com/reactnativetrackerexample/DetoxTestAppJUnitRunner.java +21 -0
  42. package/example/android/app/src/debug/AndroidManifest.xml +13 -0
  43. package/example/android/app/src/debug/java/com/reactnativetrackerexample/ReactNativeFlipper.java +75 -0
  44. package/example/android/app/src/main/AndroidManifest.xml +26 -0
  45. package/example/android/app/src/main/java/com/reactnativetrackerexample/MainActivity.java +32 -0
  46. package/example/android/app/src/main/java/com/reactnativetrackerexample/MainApplication.java +62 -0
  47. package/example/android/app/src/main/res/drawable/rn_edit_text_material.xml +36 -0
  48. package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  49. package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  50. package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  51. package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  52. package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  53. package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  54. package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  55. package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  56. package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  57. package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  58. package/example/android/app/src/main/res/values/strings.xml +3 -0
  59. package/example/android/app/src/main/res/values/styles.xml +9 -0
  60. package/example/android/app/src/release/java/com/reactnativetrackerexample/ReactNativeFlipper.java +20 -0
  61. package/example/android/build.gradle +31 -0
  62. package/example/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  63. package/example/android/gradle/wrapper/gradle-wrapper.properties +6 -0
  64. package/example/android/gradle.properties +44 -0
  65. package/example/android/gradlew +244 -0
  66. package/example/android/gradlew.bat +92 -0
  67. package/example/android/settings.gradle +4 -0
  68. package/example/app.json +4 -0
  69. package/example/babel.config.js +17 -0
  70. package/example/detox.config.js +92 -0
  71. package/example/e2e/config.json +10 -0
  72. package/example/e2e/emitEvents.e2e.detox.js +108 -0
  73. package/example/e2e/environment.js +23 -0
  74. package/example/e2e/helpers/microCommands.js +153 -0
  75. package/example/e2e/helpers/microHelpers.js +346 -0
  76. package/example/e2e/helpers/microHelpers.test.js +308 -0
  77. package/example/e2e/helpers/schemas.js +62 -0
  78. package/example/e2e/jest.config.js +16 -0
  79. package/example/e2e/setup.js +4 -0
  80. package/example/e2e/testEvents.micro.test.js +300 -0
  81. package/example/index.js +5 -0
  82. package/example/ios/.xcode.env +11 -0
  83. package/example/ios/Podfile +64 -0
  84. package/example/ios/Podfile.lock +737 -0
  85. package/example/ios/ReactNativeTrackerExample/AppDelegate.h +6 -0
  86. package/example/ios/ReactNativeTrackerExample/AppDelegate.mm +26 -0
  87. package/example/ios/ReactNativeTrackerExample/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
  88. package/example/ios/ReactNativeTrackerExample/Images.xcassets/Contents.json +6 -0
  89. package/example/ios/ReactNativeTrackerExample/Info.plist +55 -0
  90. package/example/ios/ReactNativeTrackerExample/LaunchScreen.storyboard +47 -0
  91. package/example/ios/ReactNativeTrackerExample/main.m +10 -0
  92. package/example/ios/ReactNativeTrackerExample-Bridging-Header.h +3 -0
  93. package/example/ios/ReactNativeTrackerExample.xcodeproj/project.pbxproj +722 -0
  94. package/{ios/RNSnowplowTracker.xcodeproj/xcshareddata/xcschemes/RNSnowplowTracker.xcscheme → example/ios/ReactNativeTrackerExample.xcodeproj/xcshareddata/xcschemes/ReactNativeTrackerExample.xcscheme} +29 -21
  95. package/example/ios/ReactNativeTrackerExample.xcworkspace/contents.xcworkspacedata +10 -0
  96. package/example/ios/ReactNativeTrackerExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  97. package/example/ios/ReactNativeTrackerExampleTests/Info.plist +24 -0
  98. package/example/ios/ReactNativeTrackerExampleTests/ReactNativeTrackerExampleTests.m +66 -0
  99. package/example/metro.config.js +45 -0
  100. package/example/package.json +54 -0
  101. package/example/react-native.config.js +10 -0
  102. package/example/src/App.js +557 -0
  103. package/example/tsconfig.json +5 -0
  104. package/example/yarn.lock +7379 -0
  105. package/ios/ReactNativeTracker-Bridging-Header.h +2 -0
  106. package/ios/ReactNativeTracker.mm +165 -0
  107. package/ios/ReactNativeTracker.swift +757 -0
  108. package/ios/{RNSnowplowTracker.xcodeproj → ReactNativeTracker.xcodeproj}/project.pbxproj +55 -79
  109. package/ios/Util/ConfigUtils.swift +206 -0
  110. package/ios/Util/TrackerVersion.swift +3 -0
  111. package/ios/Util/Utilities.swift +37 -0
  112. package/lefthook.yml +11 -0
  113. package/lib/commonjs/api.js +475 -0
  114. package/lib/commonjs/api.js.map +1 -0
  115. package/lib/commonjs/configurations.js +209 -0
  116. package/lib/commonjs/configurations.js.map +1 -0
  117. package/lib/commonjs/constants.js +85 -0
  118. package/lib/commonjs/constants.js.map +1 -0
  119. package/lib/commonjs/events.js +256 -0
  120. package/lib/commonjs/events.js.map +1 -0
  121. package/lib/commonjs/index.js +141 -0
  122. package/lib/commonjs/index.js.map +1 -0
  123. package/lib/commonjs/jsCore.js +393 -0
  124. package/lib/commonjs/jsCore.js.map +1 -0
  125. package/lib/commonjs/native.js +29 -0
  126. package/lib/commonjs/native.js.map +1 -0
  127. package/lib/commonjs/subject.js +248 -0
  128. package/lib/commonjs/subject.js.map +1 -0
  129. package/lib/commonjs/tracker.js +221 -0
  130. package/lib/commonjs/tracker.js.map +1 -0
  131. package/lib/commonjs/types.js +2 -0
  132. package/lib/commonjs/types.js.map +1 -0
  133. package/lib/commonjs/utils.js +85 -0
  134. package/lib/commonjs/utils.js.map +1 -0
  135. package/lib/commonjs/webViewInterface.js +79 -0
  136. package/lib/commonjs/webViewInterface.js.map +1 -0
  137. package/lib/module/api.js +439 -0
  138. package/lib/module/api.js.map +1 -0
  139. package/lib/module/configurations.js +197 -0
  140. package/lib/module/configurations.js.map +1 -0
  141. package/lib/module/constants.js +80 -0
  142. package/lib/module/constants.js.map +1 -0
  143. package/lib/module/events.js +240 -0
  144. package/lib/module/events.js.map +1 -0
  145. package/lib/module/index.js +129 -0
  146. package/lib/module/index.js.map +1 -0
  147. package/lib/module/jsCore.js +390 -0
  148. package/lib/module/jsCore.js.map +1 -0
  149. package/lib/module/native.js +25 -0
  150. package/lib/module/native.js.map +1 -0
  151. package/lib/module/subject.js +235 -0
  152. package/lib/module/subject.js.map +1 -0
  153. package/lib/module/tracker.js +209 -0
  154. package/lib/module/tracker.js.map +1 -0
  155. package/lib/module/types.js +2 -0
  156. package/lib/module/types.js.map +1 -0
  157. package/lib/module/utils.js +79 -0
  158. package/lib/module/utils.js.map +1 -0
  159. package/lib/module/webViewInterface.js +75 -0
  160. package/lib/module/webViewInterface.js.map +1 -0
  161. package/lib/typescript/__tests__/api.test.d.ts +2 -0
  162. package/lib/typescript/__tests__/api.test.d.ts.map +1 -0
  163. package/lib/typescript/__tests__/configurations.test.d.ts +2 -0
  164. package/lib/typescript/__tests__/configurations.test.d.ts.map +1 -0
  165. package/lib/typescript/__tests__/events.test.d.ts +2 -0
  166. package/lib/typescript/__tests__/events.test.d.ts.map +1 -0
  167. package/lib/typescript/__tests__/index.test.d.ts +2 -0
  168. package/lib/typescript/__tests__/index.test.d.ts.map +1 -0
  169. package/lib/typescript/__tests__/jsCore.test.d.ts +2 -0
  170. package/lib/typescript/__tests__/jsCore.test.d.ts.map +1 -0
  171. package/lib/typescript/__tests__/utils.test.d.ts +2 -0
  172. package/lib/typescript/__tests__/utils.test.d.ts.map +1 -0
  173. package/lib/typescript/api.d.ts +226 -0
  174. package/lib/typescript/api.d.ts.map +1 -0
  175. package/lib/typescript/configurations.d.ts +73 -0
  176. package/lib/typescript/configurations.d.ts.map +1 -0
  177. package/lib/typescript/constants.d.ts +59 -0
  178. package/lib/typescript/constants.d.ts.map +1 -0
  179. package/lib/typescript/events.d.ts +101 -0
  180. package/lib/typescript/events.d.ts.map +1 -0
  181. package/lib/typescript/index.d.ts +27 -0
  182. package/lib/typescript/index.d.ts.map +1 -0
  183. package/lib/typescript/jsCore.d.ts +140 -0
  184. package/lib/typescript/jsCore.d.ts.map +1 -0
  185. package/lib/typescript/native.d.ts +4 -0
  186. package/lib/typescript/native.d.ts.map +1 -0
  187. package/lib/typescript/subject.d.ts +91 -0
  188. package/lib/typescript/subject.d.ts.map +1 -0
  189. package/lib/typescript/tracker.d.ts +93 -0
  190. package/lib/typescript/tracker.d.ts.map +1 -0
  191. package/{dist/index.d.ts → lib/typescript/types.d.ts} +188 -75
  192. package/lib/typescript/types.d.ts.map +1 -0
  193. package/lib/typescript/utils.d.ts +35 -0
  194. package/lib/typescript/utils.d.ts.map +1 -0
  195. package/lib/typescript/webViewInterface.d.ts +15 -0
  196. package/lib/typescript/webViewInterface.d.ts.map +1 -0
  197. package/package.json +138 -51
  198. package/scripts/bootstrap.js +29 -0
  199. package/snowplow-react-native-tracker.podspec +42 -0
  200. package/src/__mocks__/react-native.js +7 -0
  201. package/src/__tests__/api.test.ts +34 -0
  202. package/src/__tests__/configurations.test.ts +620 -0
  203. package/src/__tests__/events.test.ts +749 -0
  204. package/src/__tests__/index.test.ts +27 -0
  205. package/src/__tests__/jsCore.test.ts +169 -0
  206. package/src/__tests__/utils.test.ts +23 -0
  207. package/src/api.ts +535 -0
  208. package/src/configurations.ts +337 -0
  209. package/src/constants.ts +102 -0
  210. package/src/events.ts +330 -0
  211. package/src/index.ts +189 -0
  212. package/src/jsCore.ts +553 -0
  213. package/src/native.ts +34 -0
  214. package/src/subject.ts +315 -0
  215. package/src/tracker.ts +330 -0
  216. package/src/types.ts +1087 -0
  217. package/src/utils.ts +78 -0
  218. package/src/webViewInterface.ts +105 -0
  219. package/tsconfig.build.json +5 -0
  220. package/tsconfig.json +28 -0
  221. package/turbo.json +34 -0
  222. package/yarn.lock +9333 -0
  223. package/RNSnowplowTracker.podspec +0 -24
  224. package/android/src/main/java/com/snowplowanalytics/react/tracker/RNSnowplowTrackerModule.java +0 -750
  225. package/android/src/main/java/com/snowplowanalytics/react/tracker/RNSnowplowTrackerPackage.java +0 -29
  226. package/android/src/main/java/com/snowplowanalytics/react/util/ConfigUtil.java +0 -351
  227. package/android/src/main/java/com/snowplowanalytics/react/util/EventUtil.java +0 -339
  228. package/android/src/main/java/com/snowplowanalytics/react/util/TrackerVersion.java +0 -7
  229. package/dist/index.js +0 -1650
  230. package/dist/index.js.map +0 -1
  231. package/ios/RNSnowplowTracker.h +0 -34
  232. package/ios/RNSnowplowTracker.m +0 -911
  233. package/ios/Util/NSDictionary+RNSP_TypeMethods.h +0 -33
  234. package/ios/Util/NSDictionary+RNSP_TypeMethods.m +0 -40
  235. package/ios/Util/RNConfigUtils.h +0 -44
  236. package/ios/Util/RNConfigUtils.m +0 -209
  237. package/ios/Util/RNTrackerVersion.h +0 -27
  238. package/ios/Util/RNTrackerVersion.m +0 -27
  239. package/ios/Util/RNUtilities.h +0 -32
  240. package/ios/Util/RNUtilities.m +0 -68
@@ -0,0 +1,153 @@
1
+ /*
2
+ * Copyright (c) 2020-2023 Snowplow Analytics Ltd. All rights reserved.
3
+ *
4
+ * This program is licensed to you under the Apache License Version 2.0,
5
+ * and you may not use this file except in compliance with the Apache License Version 2.0.
6
+ * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
7
+ *
8
+ * Unless required by applicable law or agreed to in writing,
9
+ * software distributed under the Apache License Version 2.0 is distributed on an
10
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
12
+ */
13
+
14
+ const Micro = require('./microHelpers.js');
15
+
16
+ const microUrl = '0.0.0.0';
17
+ const microPort = '9090';
18
+ const microGood = '/micro/good';
19
+ const microBad = '/micro/bad';
20
+ const microReset = '/micro/reset';
21
+
22
+ async function getMicroGood() {
23
+ const good = await Micro.requestJson(microUrl, microPort, microGood);
24
+ return good;
25
+ }
26
+
27
+ async function getMicroBad() {
28
+ const bad = await Micro.requestJson(microUrl, microPort, microBad);
29
+ return bad;
30
+ }
31
+
32
+ async function resetMicro() {
33
+ await Micro.request(microUrl, microPort, microReset);
34
+ }
35
+
36
+ /**
37
+ * setTimeout promise
38
+ *
39
+ * @param {number} millis The milliseconds to wait
40
+ */
41
+ function sleep(millis) {
42
+ return new Promise(resolve => {
43
+ setTimeout(() => resolve('done sleeping!'), millis);
44
+ });
45
+ }
46
+
47
+ /**
48
+ * Asserts no bad events
49
+ *
50
+ */
51
+ function assertNoBadEvents() {
52
+ return getMicroBad().then(res => {
53
+ expect(res.length).toBe(0);
54
+ });
55
+ }
56
+
57
+ /**
58
+ * Asserts on the number of events having a given schema
59
+ *
60
+ * ```
61
+ * eventsWithSchema("iglu:com.acme/test_event/jsonschema/1-0-0", 2);
62
+ * ```
63
+ *
64
+ * @param {string} schema The event's schema to match
65
+ * @param {number} [n=1] The expected number of matching events
66
+ */
67
+ function eventsWithSchema(schema, n = 1) {
68
+ n = parseInt(n, 10);
69
+ return getMicroGood().then(arr => {
70
+ const res = Micro.matchBySchema(arr, schema);
71
+ expect(res.length).toBe(n);
72
+ });
73
+ }
74
+
75
+ /**
76
+ * Asserts on the number of events having a given type
77
+ *
78
+ * ```
79
+ * eventsWithEventType("struct", 7);
80
+ * ```
81
+ *
82
+ * @param {string} eventType The event's type to match
83
+ * @param {number} [n=1] The expected number of matching events
84
+ */
85
+ function eventsWithEventType(eventType, n = 1) {
86
+ n = parseInt(n, 10);
87
+ return getMicroGood().then(arr => {
88
+ const res = Micro.matchByEventType(arr, eventType);
89
+ expect(res.length).toBe(n);
90
+ });
91
+ }
92
+
93
+ /**
94
+ * Asserts on the number of events having a given set of properties (schema, values, contexts, parameters)
95
+ *
96
+ * ```
97
+ * eventsWithProperties({
98
+ * schema: "iglu:com.acme/test_event/jsonschema/1-0-0",
99
+ * values: {
100
+ * testProperty: true
101
+ * },
102
+ * header: "the: header"
103
+ * contexts: [{
104
+ * schema: "iglu:com.acme/test_context/jsonschema/1-0-0",
105
+ * data: {
106
+ * "testCoProp": 0,
107
+ * }
108
+ * }],
109
+ * parameters: {
110
+ * user_id: "tester",
111
+ * name_tracker: "myTrackerName"
112
+ * }
113
+ * }, 3);
114
+ * ```
115
+ *
116
+ * @param {Object} eventOptions The options to match against
117
+ * @param {number} [n=1] The expected number of matching events
118
+ */
119
+ function eventsWithProperties(eventOptions, n = 1) {
120
+ n = parseInt(n, 10);
121
+ return getMicroGood().then(arr => {
122
+ const res = Micro.matchEvents(arr, eventOptions);
123
+ expect(res.length).toBe(n);
124
+ });
125
+ }
126
+
127
+ /**
128
+ * Asserts on the number of events having a given HTTP request header
129
+ *
130
+ * ```
131
+ * eventsWithHeader("Connection: keep-alive", 2);
132
+ * ```
133
+ *
134
+ * @param {string} header The request header to match
135
+ * @param {number} [n=1] The expected number of matching events
136
+ */
137
+ function eventsWithHeader(header, n = 1) {
138
+ n = parseInt(n, 10);
139
+ return getMicroGood().then(arr => {
140
+ const res = Micro.matchByHeader(arr, header);
141
+ expect(res.length).toBe(n);
142
+ });
143
+ }
144
+
145
+ module.exports = {
146
+ assertNoBadEvents,
147
+ eventsWithSchema,
148
+ eventsWithEventType,
149
+ eventsWithProperties,
150
+ eventsWithHeader,
151
+ resetMicro,
152
+ sleep,
153
+ };
@@ -0,0 +1,346 @@
1
+ /*
2
+ * Copyright (c) 2020-2023 Snowplow Analytics Ltd. All rights reserved.
3
+ *
4
+ * This program is licensed to you under the Apache License Version 2.0,
5
+ * and you may not use this file except in compliance with the Apache License Version 2.0.
6
+ * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
7
+ *
8
+ * Unless required by applicable law or agreed to in writing,
9
+ * software distributed under the Apache License Version 2.0 is distributed on an
10
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
12
+ */
13
+
14
+ const http = require('http');
15
+
16
+ /**
17
+ * Makes an http get request
18
+ *
19
+ * @param {string} url
20
+ * @param {string} port
21
+ * @param {string} path
22
+ */
23
+ function request(url, port, path) {
24
+ return new Promise((resolve, reject) => {
25
+ const options = {
26
+ hostname: url,
27
+ port: port,
28
+ path: path,
29
+ };
30
+ try {
31
+ http.get(options, res => {
32
+ let data = '';
33
+ res.on('data', d => (data += d));
34
+ res.on('end', () => resolve(data));
35
+ });
36
+ } catch (e) {
37
+ reject(e);
38
+ }
39
+ });
40
+ }
41
+
42
+ /**
43
+ * Returns a JSON parsed response from an http request
44
+ *
45
+ * @param {string} url
46
+ * @param {string} port
47
+ * @param {string} path
48
+ */
49
+ function requestJson(url, port, path) {
50
+ return request(url, port, path).then(g => JSON.parse(g));
51
+ }
52
+
53
+ /**
54
+ * Filters an array of Snowplow events based on eventType
55
+ *
56
+ * ```
57
+ * matchByEventType(goodEventsArray, "page_view");
58
+ *
59
+ * ```
60
+ * @param {Array} eventsArray An array of Snowplow events
61
+ * @param {string} eventType The eventType to match
62
+ * @returns {Array} An array with the matching events
63
+ */
64
+ function matchByEventType(eventsArray, eventType) {
65
+ return eventsArray.filter(hasEventType(eventType));
66
+ }
67
+
68
+ /**
69
+ * Filters an array of Snowplow events based on schema
70
+ *
71
+ * ```
72
+ * matchBySchema(goodEventsArray, "iglu:com.acme/test_event/jsonschema/1-0-0");
73
+ * ```
74
+ *
75
+ * @param {Array} eventsArray An array of Snowplow events
76
+ * @param {string} schema The schema to match
77
+ * @returns {Array} An array with the matching events
78
+ */
79
+ function matchBySchema(eventsArray, schema) {
80
+ return eventsArray.filter(hasSchema(schema));
81
+ }
82
+
83
+ /**
84
+ * Filters an array of unstructured Snowplow events based on data values
85
+ *
86
+ * ```
87
+ * matchByVals(goodEventsArray, {targetUrl: "https://docs.snowplowanalytics.com/"});
88
+ * ```
89
+ *
90
+ * @param {Array} eventsArray An array of unstructured Snowplow events
91
+ * @param {Object} valsObj The object having as keys the data fields to match
92
+ * @returns {Array} An array with the matching events
93
+ */
94
+ function matchByVals(eventsArray, valsObj) {
95
+ return eventsArray.filter(hasValues(valsObj));
96
+ }
97
+
98
+ /**
99
+ * Filters an array of Snowplow events based on parameter values
100
+ *
101
+ * ```
102
+ * matchByParams(goodEventsArray,
103
+ * {
104
+ * event: "struct",
105
+ * se_category: "Mixes",
106
+ * se_action: "Play",
107
+ * });
108
+ * ```
109
+ *
110
+ * @param {Array} eventsArray An array of Snowplow events
111
+ * @param {Object} paramsObj An object having as keys the event parameters to match
112
+ * @returns {Array} An array with the matching events
113
+ */
114
+ function matchByParams(eventsArray, paramsObj) {
115
+ return eventsArray.filter(hasParams(paramsObj));
116
+ }
117
+
118
+ /**
119
+ * Filters an array of Snowplow events based on an array of attached contexts
120
+ *
121
+ * ```
122
+ * matchByContexts(goodEventsArray,
123
+ * [{
124
+ * schema: "iglu:com.acme/a_test_context/jsonschema/1-0-0",
125
+ * data: {"testprop": 0}
126
+ * },{
127
+ * schema: "iglu:com.acme/b_test_context/jsonschema/1-0-0"
128
+ * }]);
129
+ * ```
130
+ *
131
+ * @param {Array} eventsArray An array of Snowplow events
132
+ * @param {Array} expectedContextsArray An array of contexts
133
+ * @returns {Array} An array with the matching events
134
+ */
135
+ function matchByContexts(eventsArray, expectedContextsArray) {
136
+ return eventsArray.filter(hasContexts(expectedContextsArray));
137
+ }
138
+
139
+ /**
140
+ * Filters an array of Snowplow events based on the request headers
141
+ *
142
+ * ```
143
+ * matchByHeader(goodEventsArray, "Connection: keep-alive");
144
+ *
145
+ * ```
146
+ * @param {Array} eventsArray An array of Snowplow events
147
+ * @param {string} header The HTTP request header to match
148
+ * @returns {Array} An array with the matching events
149
+ */
150
+ function matchByHeader(eventsArray, header) {
151
+ return eventsArray.filter(hasHeader(header));
152
+ }
153
+
154
+ /**
155
+ * Filters an array of Snowplow events based on event's Properties
156
+ *
157
+ * ```
158
+ * matchEvents(goodEventsArray,
159
+ * {
160
+ * schema: "iglu:com.acme/test_event/jsonschema/1-0-0",
161
+ * values: {
162
+ * testProperty: true
163
+ * },
164
+ * contexts: [{
165
+ * schema: "iglu:com.acme/test_context/jsonschema/1-0-0",
166
+ * data: {
167
+ * testCoProp: 0,
168
+ * }
169
+ * }],
170
+ * parameters: {
171
+ * user_id: "tester",
172
+ * name_tracker: "myTrackerName"
173
+ * },
174
+ * header: 'the: header',
175
+ * });
176
+ * ```
177
+ *
178
+ * @param {Array} microEvents An array of Snowplow events
179
+ * @param {Properties} eventProps The event properties to match against
180
+ * @returns {Array} An array with the matching events
181
+ */
182
+ function matchEvents(microEvents, eventProps) {
183
+ if (Object.prototype.toString.call(microEvents) !== '[object Array]') {
184
+ microEvents = [microEvents];
185
+ }
186
+
187
+ let res = microEvents;
188
+
189
+ if (eventProps.eventType) {
190
+ res = matchByEventType(res, eventProps.eventType);
191
+ }
192
+
193
+ if (eventProps.schema) {
194
+ res = matchBySchema(res, eventProps.schema);
195
+ }
196
+
197
+ if (eventProps.values) {
198
+ res = matchByVals(res, eventProps.values);
199
+ }
200
+
201
+ if (eventProps.contexts) {
202
+ res = matchByContexts(res, eventProps.contexts);
203
+ }
204
+
205
+ if (eventProps.parameters) {
206
+ res = matchByParams(res, eventProps.parameters);
207
+ }
208
+
209
+ if (eventProps.header) {
210
+ res = matchByHeader(res, eventProps.header);
211
+ }
212
+
213
+ return res;
214
+ }
215
+
216
+ function hasEventType(evType) {
217
+ return function (ev) {
218
+ return ev.eventType === evType;
219
+ };
220
+ }
221
+
222
+ function hasSchema(schema) {
223
+ return function (ev) {
224
+ if (ev.eventType === 'unstruct') {
225
+ let unstruct_ev = ev.event.unstruct_event;
226
+
227
+ return unstruct_ev.data.schema === schema;
228
+ } else {
229
+ return false;
230
+ }
231
+ };
232
+ }
233
+
234
+ function hasValues(values) {
235
+ return function (ev) {
236
+ if (ev.eventType === 'unstruct') {
237
+ let unstruct_ev = ev.event.unstruct_event;
238
+ let data = unstruct_ev.data.data;
239
+
240
+ return (
241
+ Object.keys(values).every(keyIncludedIn(data)) &&
242
+ Object.keys(values).every(comparesIn(values, data))
243
+ );
244
+ } else {
245
+ return false;
246
+ }
247
+ };
248
+ }
249
+
250
+ function hasParams(expectParams) {
251
+ return function (ev) {
252
+ let actualParams = ev.event;
253
+
254
+ return (
255
+ Object.keys(expectParams).every(keyIncludedIn(actualParams)) &&
256
+ Object.keys(expectParams).every(comparesIn(expectParams, actualParams))
257
+ );
258
+ };
259
+ }
260
+
261
+ function hasContexts(expCoArr) {
262
+ return function (ev) {
263
+ let evCo = ev.event.contexts;
264
+
265
+ if (evCo.hasOwnProperty('data')) {
266
+ let actCoArr = evCo.data;
267
+
268
+ return compare(expCoArr, actCoArr);
269
+ } else {
270
+ return false;
271
+ }
272
+ };
273
+ }
274
+
275
+ function hasHeader(header) {
276
+ return function (ev) {
277
+ return ev.rawEvent.context.headers.includes(header);
278
+ };
279
+ }
280
+
281
+ function keyIncludedIn(obj) {
282
+ return function (key) {
283
+ return Object.keys(obj).includes(key);
284
+ };
285
+ }
286
+
287
+ function comparesIn(expected, actual) {
288
+ return function (key) {
289
+ let expValue = expected[key];
290
+ let actValue = actual[key];
291
+
292
+ return compare(expValue, actValue);
293
+ };
294
+ }
295
+
296
+ /**
297
+ * A function to deep compare (equality for primitive data types and containership for Objects and Arrays)
298
+ *
299
+ * ```
300
+ * compare(1, 1); // true
301
+ * compare(1, "1"); // false
302
+ * compare([1, 2], [3, 1, 2]); // true
303
+ * compare({a:1, b:2}, {b:2, c:3, a:1}); // true
304
+ * compare([1, [2]], [[3, 2], 1, 4]); // true
305
+ * compare({a: [1, 2], b: {c:3}}, {b: {d:4, c:3}, a:[3, 2, 1]}); // true
306
+ * ```
307
+ *
308
+ * @param {*} expVal The expected value
309
+ * @param {*} actVal The actual value
310
+ * @returns {Boolean} Whether the expVal is equal to or deeply contained in actVal
311
+ */
312
+ function compare(expVal, actVal) {
313
+ let expType = Object.prototype.toString.call(expVal);
314
+ let actType = Object.prototype.toString.call(actVal);
315
+
316
+ if (expVal === null) {
317
+ return actVal === null;
318
+ } else if (expType !== actType) {
319
+ return false;
320
+ } else if (expType === '[object Array]') {
321
+ return expVal.every(function (e) {
322
+ return actVal.some(function (a) {
323
+ return compare(e, a);
324
+ });
325
+ });
326
+ } else if (expType === '[object Object]') {
327
+ return Object.keys(expVal).every(function (k) {
328
+ return Object.keys(actVal).includes(k) && compare(expVal[k], actVal[k]);
329
+ });
330
+ } else {
331
+ return expVal === actVal;
332
+ }
333
+ }
334
+
335
+ module.exports = {
336
+ matchByEventType,
337
+ matchBySchema,
338
+ matchByVals,
339
+ matchByParams,
340
+ matchByContexts,
341
+ matchByHeader,
342
+ matchEvents,
343
+ compare,
344
+ request,
345
+ requestJson,
346
+ };