@snowplow/react-native-tracker 1.4.0 → 2.1.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 +155 -0
  8. package/.github/workflows/deploy.yml +97 -0
  9. package/.github/workflows/e2e-android.yml +121 -0
  10. package/.github/workflows/e2e-ios.yml +95 -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 +176 -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 +744 -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 +274 -0
  32. package/android/src/main/java/com/snowplow/reactnativetracker/util/EventUtil.kt +233 -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 +95 -0
  73. package/example/e2e/environment.js +23 -0
  74. package/example/e2e/helpers/microCommands.js +140 -0
  75. package/example/e2e/helpers/microHelpers.js +333 -0
  76. package/example/e2e/helpers/microHelpers.test.js +295 -0
  77. package/example/e2e/helpers/schemas.js +49 -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 +287 -0
  81. package/example/index.js +5 -0
  82. package/example/ios/.xcode.env +11 -0
  83. package/example/ios/Podfile +62 -0
  84. package/example/ios/Podfile.lock +730 -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 +566 -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 +175 -0
  107. package/ios/ReactNativeTracker.swift +822 -0
  108. package/ios/{RNSnowplowTracker.xcodeproj → ReactNativeTracker.xcodeproj}/project.pbxproj +55 -79
  109. package/ios/Util/ConfigUtils.swift +209 -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 +490 -0
  114. package/lib/commonjs/api.js.map +1 -0
  115. package/lib/commonjs/configurations.js +196 -0
  116. package/lib/commonjs/configurations.js.map +1 -0
  117. package/lib/commonjs/constants.js +77 -0
  118. package/lib/commonjs/constants.js.map +1 -0
  119. package/lib/commonjs/events.js +277 -0
  120. package/lib/commonjs/events.js.map +1 -0
  121. package/lib/commonjs/index.js +132 -0
  122. package/lib/commonjs/index.js.map +1 -0
  123. package/lib/commonjs/jsCore.js +427 -0
  124. package/lib/commonjs/jsCore.js.map +1 -0
  125. package/lib/commonjs/native.js +16 -0
  126. package/lib/commonjs/native.js.map +1 -0
  127. package/lib/commonjs/subject.js +235 -0
  128. package/lib/commonjs/subject.js.map +1 -0
  129. package/lib/commonjs/tracker.js +248 -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 +72 -0
  134. package/lib/commonjs/utils.js.map +1 -0
  135. package/lib/commonjs/webViewInterface.js +66 -0
  136. package/lib/commonjs/webViewInterface.js.map +1 -0
  137. package/lib/module/api.js +452 -0
  138. package/lib/module/api.js.map +1 -0
  139. package/lib/module/configurations.js +184 -0
  140. package/lib/module/configurations.js.map +1 -0
  141. package/lib/module/constants.js +72 -0
  142. package/lib/module/constants.js.map +1 -0
  143. package/lib/module/events.js +259 -0
  144. package/lib/module/events.js.map +1 -0
  145. package/lib/module/index.js +120 -0
  146. package/lib/module/index.js.map +1 -0
  147. package/lib/module/jsCore.js +424 -0
  148. package/lib/module/jsCore.js.map +1 -0
  149. package/lib/module/native.js +12 -0
  150. package/lib/module/native.js.map +1 -0
  151. package/lib/module/subject.js +222 -0
  152. package/lib/module/subject.js.map +1 -0
  153. package/lib/module/tracker.js +234 -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 +66 -0
  158. package/lib/module/utils.js.map +1 -0
  159. package/lib/module/webViewInterface.js +62 -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 +240 -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 +64 -0
  178. package/lib/typescript/constants.d.ts.map +1 -0
  179. package/lib/typescript/events.d.ts +115 -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 +152 -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 +111 -0
  190. package/lib/typescript/tracker.d.ts.map +1 -0
  191. package/{dist/index.d.ts → lib/typescript/types.d.ts} +264 -73
  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 +135 -53
  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 +21 -0
  202. package/src/__tests__/configurations.test.ts +608 -0
  203. package/src/__tests__/events.test.ts +736 -0
  204. package/src/__tests__/index.test.ts +14 -0
  205. package/src/__tests__/jsCore.test.ts +199 -0
  206. package/src/__tests__/utils.test.ts +10 -0
  207. package/src/api.ts +556 -0
  208. package/src/configurations.ts +325 -0
  209. package/src/constants.ts +97 -0
  210. package/src/events.ts +355 -0
  211. package/src/index.ts +184 -0
  212. package/src/jsCore.ts +603 -0
  213. package/src/native.ts +21 -0
  214. package/src/subject.ts +302 -0
  215. package/src/tracker.ts +377 -0
  216. package/src/types.ts +1162 -0
  217. package/src/utils.ts +65 -0
  218. package/src/webViewInterface.ts +92 -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 -2026
  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,14 @@
1
+ import * as main from '../index';
2
+ import * as api from '../api';
3
+
4
+ jest.mock('../../src/api');
5
+
6
+ describe('test 0', () => {
7
+ test('test 0 1', () => {
8
+ const mockApi = api as jest.Mocked<typeof api>;
9
+
10
+ main.createTracker('sp1', { endpoint: 'http://0.0.0.0:9090' });
11
+
12
+ expect(mockApi.createTracker).toHaveBeenCalled();
13
+ });
14
+ });
@@ -0,0 +1,199 @@
1
+ import type { Payload } from '@snowplow/tracker-core';
2
+ import type { InitTrackerConfiguration } from '../types';
3
+ import { JSSnowplowTracker } from '../jsCore';
4
+
5
+ async function createTracker(
6
+ configuration: InitTrackerConfiguration,
7
+ callback?: () => Promise<void>
8
+ ): Promise<Payload[]> {
9
+ if (configuration.trackerConfig) {
10
+ configuration.trackerConfig.base64Encoding = false;
11
+ } else {
12
+ configuration.trackerConfig = { base64Encoding: false };
13
+ }
14
+
15
+ const trackedPayloads: Payload[] = [];
16
+ const emitter = (payload: Payload): void => {
17
+ trackedPayloads.push(payload);
18
+ };
19
+ await JSSnowplowTracker.createTracker(configuration, emitter);
20
+ if (callback) {
21
+ await callback();
22
+ }
23
+
24
+ return trackedPayloads;
25
+ }
26
+ describe('test jsCore', () => {
27
+ beforeEach(async () => {
28
+ await JSSnowplowTracker.removeAllTrackers();
29
+ });
30
+
31
+ test('sets Subject properties and tracks structured event', async () => {
32
+ const trackedPayloads = await createTracker(
33
+ {
34
+ namespace: 'ns',
35
+ networkConfig: { endpoint: 'http://localhost' },
36
+ subjectConfig: {
37
+ userId: 'user1',
38
+ },
39
+ },
40
+ async () => {
41
+ await JSSnowplowTracker.trackStructuredEvent({
42
+ tracker: 'ns',
43
+ eventData: { category: 'cat', action: 'act' },
44
+ contexts: [],
45
+ });
46
+ }
47
+ );
48
+
49
+ expect(trackedPayloads.length).toBe(1);
50
+ expect(trackedPayloads[0]?.uid).toEqual('user1');
51
+ expect(trackedPayloads[0]?.se_ca).toEqual('cat');
52
+ expect(trackedPayloads[0]?.se_ac).toEqual('act');
53
+ });
54
+
55
+ test('tracks screen view event with default tracker', async () => {
56
+ const trackedPayloads = await createTracker(
57
+ {
58
+ namespace: 'ns',
59
+ networkConfig: { endpoint: 'http://localhost' },
60
+ },
61
+ async () => {
62
+ await JSSnowplowTracker.trackScreenViewEvent({
63
+ tracker: null,
64
+ eventData: { id: 'id1', name: 'screen' },
65
+ contexts: [],
66
+ });
67
+ }
68
+ );
69
+
70
+ expect(trackedPayloads.length).toBe(1);
71
+ expect(trackedPayloads[0]?.tna).toEqual('ns');
72
+ expect(trackedPayloads[0]?.ue_pr ?? '').toContain('"name":"screen"');
73
+ });
74
+
75
+ test('tracks scroll changed event with default tracker', async () => {
76
+ const trackedPayloads = await createTracker(
77
+ {
78
+ namespace: 'ns',
79
+ networkConfig: { endpoint: 'http://localhost' },
80
+ },
81
+ async () => {
82
+ await JSSnowplowTracker.trackScrollChangedEvent({
83
+ tracker: null,
84
+ eventData: { viewHeight: 100, contentHeight: 200, yOffset: 50 },
85
+ contexts: [],
86
+ });
87
+ }
88
+ );
89
+
90
+ expect(trackedPayloads.length).toBe(1);
91
+ expect(trackedPayloads[0]?.tna).toEqual('ns');
92
+ expect(trackedPayloads[0]?.ue_pr ?? '').toContain('"view_height":100');
93
+ expect(trackedPayloads[0]?.ue_pr ?? '').toContain('"content_height":200');
94
+ expect(trackedPayloads[0]?.ue_pr ?? '').toContain('"y_offset":50');
95
+ });
96
+
97
+ test('tracks list item view event with default tracker', async () => {
98
+ const trackedPayloads = await createTracker(
99
+ {
100
+ namespace: 'ns',
101
+ networkConfig: { endpoint: 'http://localhost' },
102
+ },
103
+ async () => {
104
+ await JSSnowplowTracker.trackListItemViewEvent({
105
+ tracker: null,
106
+ eventData: { index: 2, itemsCount: 10 },
107
+ contexts: [],
108
+ });
109
+ }
110
+ );
111
+
112
+ expect(trackedPayloads.length).toBe(1);
113
+ expect(trackedPayloads[0]?.tna).toEqual('ns');
114
+ expect(trackedPayloads[0]?.ue_pr ?? '').toContain('"index":2');
115
+ expect(trackedPayloads[0]?.ue_pr ?? '').toContain('"items_count":10');
116
+ });
117
+
118
+ test('works with multiple trackers', async () => {
119
+ const tracker1Payloads = await createTracker({
120
+ namespace: 'ns1',
121
+ networkConfig: { endpoint: 'e1' },
122
+ });
123
+ expect(tracker1Payloads.length).toBe(0);
124
+
125
+ const tracker2Payloads = await createTracker(
126
+ {
127
+ namespace: 'ns2',
128
+ networkConfig: { endpoint: 'e2' },
129
+ },
130
+ async () => {
131
+ // track with default tracker
132
+ await JSSnowplowTracker.trackPageViewEvent({
133
+ tracker: null,
134
+ eventData: { pageUrl: 'p1' },
135
+ contexts: [],
136
+ });
137
+ // track with tracker 2
138
+ await JSSnowplowTracker.trackPageViewEvent({
139
+ tracker: 'ns2',
140
+ eventData: { pageUrl: 'p2' },
141
+ contexts: [],
142
+ });
143
+ // track with tracker 1
144
+ await JSSnowplowTracker.trackPageViewEvent({
145
+ tracker: 'ns1',
146
+ eventData: { pageUrl: 'p3' },
147
+ contexts: [],
148
+ });
149
+ }
150
+ );
151
+
152
+ expect(tracker1Payloads.length).toBe(2);
153
+ expect(tracker2Payloads.length).toBe(1);
154
+ expect(tracker2Payloads[0]?.url).toEqual('p2');
155
+ });
156
+
157
+ test('set user ID for initialized tracker', async () => {
158
+ const payloads = await createTracker({
159
+ namespace: 'ns1',
160
+ networkConfig: { endpoint: 'e' },
161
+ subjectConfig: { userId: 'shouldChange' },
162
+ });
163
+ await JSSnowplowTracker.setUserId({ tracker: 'ns1', userId: 'theUser' });
164
+ await JSSnowplowTracker.trackDeepLinkReceivedEvent({
165
+ tracker: 'ns1',
166
+ eventData: { url: 'https://apple.com' },
167
+ contexts: [],
168
+ });
169
+
170
+ expect(payloads.length).toBe(1);
171
+ expect(payloads[0]?.uid).toEqual('theUser');
172
+ });
173
+
174
+ test('adds context entities to events', async () => {
175
+ const payloads = await createTracker(
176
+ { namespace: 'ns1', networkConfig: { endpoint: 'e' } },
177
+ async () => {
178
+ await JSSnowplowTracker.trackEcommerceTransactionEvent({
179
+ tracker: null,
180
+ eventData: {
181
+ orderId: 'o1',
182
+ totalValue: 10,
183
+ items: [],
184
+ },
185
+ contexts: [
186
+ {
187
+ schema:
188
+ 'iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-1',
189
+ data: { targetUrl: 'http://a-target-url.com' },
190
+ },
191
+ ],
192
+ });
193
+ }
194
+ );
195
+
196
+ expect(payloads.length).toBe(1);
197
+ expect(payloads[0]?.co).toContain('"targetUrl":"http://a-target-url.com"');
198
+ });
199
+ });
@@ -0,0 +1,10 @@
1
+ import * as u from '../utils';
2
+
3
+ describe('test isObject', () => {
4
+ test('isObject', () => {
5
+ expect(u.isObject(null)).toBe(false);
6
+ expect(u.isObject(undefined)).toBe(false);
7
+ expect(u.isObject([])).toBe(false);
8
+ expect(u.isObject({})).toBe(true);
9
+ });
10
+ });