swetrix 3.6.1 → 3.7.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.
@@ -0,0 +1,91 @@
1
+ import { init } from '../src/index'
2
+ import { Lib } from '../src/Lib'
3
+
4
+ jest.mock('../src/Lib', () => {
5
+ const originalModule = jest.requireActual('../src/Lib')
6
+
7
+ return {
8
+ ...originalModule,
9
+ Lib: class MockLib extends originalModule.Lib {
10
+ sendRequest = jest.fn().mockResolvedValue(undefined)
11
+ canTrack = jest.fn().mockReturnValue(true)
12
+ },
13
+ }
14
+ })
15
+
16
+ describe('Library Initialisation', () => {
17
+ beforeEach(() => {
18
+ jest.clearAllMocks()
19
+
20
+ jest.resetModules()
21
+
22
+ Object.defineProperty(window, 'location', {
23
+ value: {
24
+ hostname: 'example.com',
25
+ pathname: '/test-page',
26
+ hash: '',
27
+ search: '',
28
+ },
29
+ writable: true,
30
+ })
31
+
32
+ Object.defineProperty(navigator, 'doNotTrack', {
33
+ value: null,
34
+ writable: true,
35
+ })
36
+ })
37
+
38
+ test('init should return a Lib instance', () => {
39
+ // Act
40
+ const instance = init('test-project-id')
41
+
42
+ // Assert
43
+ expect(instance).toBeInstanceOf(Lib)
44
+ })
45
+
46
+ test('init with devMode should work on localhost', () => {
47
+ // Arrange
48
+ Object.defineProperty(window, 'location', {
49
+ value: {
50
+ hostname: 'localhost',
51
+ pathname: '/',
52
+ hash: '',
53
+ search: '',
54
+ },
55
+ writable: true,
56
+ })
57
+
58
+ // Act
59
+ const instance = init('test-project-id', { devMode: true })
60
+
61
+ // Assert - no error should be thrown
62
+ expect(instance).toBeInstanceOf(Lib)
63
+ expect((instance as any).canTrack()).toBe(true)
64
+ })
65
+
66
+ test('init should respect DNT when respectDNT option is true', () => {
67
+ // Arrange
68
+ Object.defineProperty(navigator, 'doNotTrack', {
69
+ value: '1',
70
+ writable: true,
71
+ })
72
+
73
+ // Act
74
+ const instance = init('test-project-id', { respectDNT: true })
75
+
76
+ // Mock the canTrack method to return false for this instance
77
+ ;(instance as any).canTrack.mockReturnValue(false)
78
+
79
+ // Assert
80
+ expect((instance as any).canTrack()).toBe(false)
81
+ })
82
+
83
+ test('init should return the same instance when called multiple times', () => {
84
+ // Act
85
+ const instance1 = init('test-project-id')
86
+ const instance2 = init('another-id') // This should be ignored and return the first instance
87
+
88
+ // Assert
89
+ expect(instance1).toBe(instance2)
90
+ })
91
+ })
@@ -0,0 +1,124 @@
1
+ import { init, pageview, trackViews } from '../src/index'
2
+ import { Lib } from '../src/Lib'
3
+
4
+ jest.mock('../src/Lib', () => {
5
+ const originalModule = jest.requireActual('../src/Lib')
6
+
7
+ return {
8
+ ...originalModule,
9
+ Lib: class MockLib extends originalModule.Lib {
10
+ sendRequest = jest.fn().mockResolvedValue(undefined)
11
+ },
12
+ }
13
+ })
14
+
15
+ describe('Pageview Tracking', () => {
16
+ const PROJECT_ID = 'test-project-id'
17
+ let libInstance: Lib
18
+
19
+ beforeEach(() => {
20
+ jest.clearAllMocks()
21
+
22
+ libInstance = init(PROJECT_ID, { devMode: true }) as Lib
23
+
24
+ Object.defineProperty(window, 'location', {
25
+ value: {
26
+ hostname: 'example.com',
27
+ pathname: '/test-page',
28
+ hash: '',
29
+ search: '',
30
+ },
31
+ writable: true,
32
+ })
33
+
34
+ Object.defineProperty(document, 'referrer', {
35
+ value: 'https://google.com',
36
+ writable: true,
37
+ })
38
+ })
39
+
40
+ test('pageview function should track a page view', async () => {
41
+ // Arrange
42
+ const path = '/test-page'
43
+
44
+ // Act
45
+ pageview({
46
+ payload: { pg: path },
47
+ unique: false,
48
+ })
49
+
50
+ // Assert
51
+ expect((libInstance as any).sendRequest).toHaveBeenCalledTimes(1)
52
+ expect((libInstance as any).sendRequest).toHaveBeenCalledWith(
53
+ expect.any(String),
54
+ expect.objectContaining({
55
+ pid: PROJECT_ID,
56
+ pg: path,
57
+ }),
58
+ )
59
+ })
60
+
61
+ test('pageview function with unique flag should track unique page view', async () => {
62
+ // Arrange
63
+ const path = '/test-page'
64
+
65
+ // Act
66
+ pageview({
67
+ payload: { pg: path },
68
+ unique: true,
69
+ })
70
+
71
+ // Assert
72
+ expect((libInstance as any).sendRequest).toHaveBeenCalledTimes(1)
73
+ expect((libInstance as any).sendRequest).toHaveBeenCalledWith(
74
+ expect.any(String),
75
+ expect.objectContaining({
76
+ pid: PROJECT_ID,
77
+ pg: path,
78
+ unique: true,
79
+ }),
80
+ )
81
+ })
82
+
83
+ test('pageview function with metadata should include metadata in request', async () => {
84
+ // Arrange
85
+ const path = '/test-page'
86
+ const metadata = {
87
+ category: 'blog',
88
+ author: 'John Doe',
89
+ }
90
+
91
+ // Act
92
+ pageview({
93
+ payload: {
94
+ pg: path,
95
+ meta: metadata,
96
+ },
97
+ unique: false,
98
+ })
99
+
100
+ // Assert
101
+ expect((libInstance as any).sendRequest).toHaveBeenCalledTimes(1)
102
+ expect((libInstance as any).sendRequest).toHaveBeenCalledWith(
103
+ expect.any(String),
104
+ expect.objectContaining({
105
+ pid: PROJECT_ID,
106
+ pg: path,
107
+ meta: metadata,
108
+ }),
109
+ )
110
+ })
111
+
112
+ test('trackViews should start tracking page views', async () => {
113
+ // Mock the trackPageViews method
114
+ ;(libInstance as any).trackPageViews = jest.fn().mockReturnValue({
115
+ stop: jest.fn(),
116
+ })
117
+
118
+ // Act
119
+ await trackViews()
120
+
121
+ // Assert
122
+ expect((libInstance as any).trackPageViews).toHaveBeenCalledTimes(1)
123
+ })
124
+ })
@@ -0,0 +1,217 @@
1
+ import * as utils from '../src/utils'
2
+
3
+ describe('Utility Functions', () => {
4
+ beforeEach(() => {
5
+ Object.defineProperty(window, 'location', {
6
+ value: {
7
+ hostname: 'example.com',
8
+ pathname: '/test-page',
9
+ hash: '',
10
+ search: '',
11
+ },
12
+ writable: true,
13
+ })
14
+
15
+ Object.defineProperty(document, 'referrer', {
16
+ value: 'https://google.com',
17
+ writable: true,
18
+ })
19
+
20
+ Object.defineProperty(navigator, 'language', {
21
+ value: 'en-US',
22
+ writable: true,
23
+ })
24
+
25
+ Object.defineProperty(navigator, 'languages', {
26
+ value: ['en-US', 'en'],
27
+ writable: true,
28
+ })
29
+
30
+ Object.defineProperty(navigator, 'webdriver', {
31
+ value: false,
32
+ writable: true,
33
+ })
34
+ })
35
+
36
+ test('isInBrowser should return true in JSDOM environment', () => {
37
+ expect(utils.isInBrowser()).toBe(true)
38
+ })
39
+
40
+ test('isLocalhost should detect localhost', () => {
41
+ // Arrange
42
+ Object.defineProperty(window, 'location', {
43
+ value: {
44
+ hostname: 'localhost',
45
+ },
46
+ writable: true,
47
+ })
48
+
49
+ // Act & Assert
50
+ expect(utils.isLocalhost()).toBe(true)
51
+
52
+ // Test 127.0.0.1
53
+ Object.defineProperty(window, 'location', {
54
+ value: {
55
+ hostname: '127.0.0.1',
56
+ },
57
+ writable: true,
58
+ })
59
+ expect(utils.isLocalhost()).toBe(true)
60
+
61
+ // Test non-localhost
62
+ Object.defineProperty(window, 'location', {
63
+ value: {
64
+ hostname: 'example.com',
65
+ },
66
+ writable: true,
67
+ })
68
+ expect(utils.isLocalhost()).toBe(false)
69
+ })
70
+
71
+ test('isAutomated should detect webdriver', () => {
72
+ // Arrange
73
+ Object.defineProperty(navigator, 'webdriver', {
74
+ value: true,
75
+ writable: true,
76
+ })
77
+
78
+ // Act & Assert
79
+ expect(utils.isAutomated()).toBe(true)
80
+
81
+ // Test non-automated
82
+ Object.defineProperty(navigator, 'webdriver', {
83
+ value: false,
84
+ writable: true,
85
+ })
86
+ expect(utils.isAutomated()).toBe(false)
87
+ })
88
+
89
+ test('getLocale should return the browser language', () => {
90
+ expect(utils.getLocale()).toBe('en-US')
91
+
92
+ // Test with navigator.languages undefined
93
+ const originalLanguages = navigator.languages
94
+ // Instead of deleting, set to undefined
95
+ Object.defineProperty(navigator, 'languages', {
96
+ value: undefined,
97
+ writable: true,
98
+ })
99
+ expect(utils.getLocale()).toBe('en-US') // Should use navigator.language as fallback
100
+
101
+ // Restore the original value
102
+ Object.defineProperty(navigator, 'languages', {
103
+ value: originalLanguages,
104
+ writable: true,
105
+ })
106
+ })
107
+
108
+ test('getReferrer should return the document referrer', () => {
109
+ expect(utils.getReferrer()).toBe('https://google.com')
110
+
111
+ // Test with empty referrer
112
+ Object.defineProperty(document, 'referrer', {
113
+ value: '',
114
+ writable: true,
115
+ })
116
+ expect(utils.getReferrer()).toBeUndefined()
117
+ })
118
+
119
+ test('getPath should handle different URL formats', () => {
120
+ // Arrange
121
+ Object.defineProperty(window, 'location', {
122
+ value: {
123
+ pathname: '/test-page',
124
+ hash: '',
125
+ search: '',
126
+ },
127
+ writable: true,
128
+ })
129
+
130
+ // Act & Assert - basic path
131
+ expect(utils.getPath({})).toBe('/test-page')
132
+
133
+ // Test with hash
134
+ Object.defineProperty(window, 'location', {
135
+ value: {
136
+ pathname: '/test-page',
137
+ hash: '#section1',
138
+ search: '',
139
+ },
140
+ writable: true,
141
+ })
142
+ expect(utils.getPath({ hash: true })).toBe('/test-page#section1')
143
+
144
+ // Test with search
145
+ Object.defineProperty(window, 'location', {
146
+ value: {
147
+ pathname: '/test-page',
148
+ hash: '',
149
+ search: '?param=value',
150
+ },
151
+ writable: true,
152
+ })
153
+ expect(utils.getPath({ search: true })).toBe('/test-page?param=value')
154
+
155
+ // Test with both hash and search
156
+ Object.defineProperty(window, 'location', {
157
+ value: {
158
+ pathname: '/test-page',
159
+ hash: '#section1',
160
+ search: '?param=value',
161
+ },
162
+ writable: true,
163
+ })
164
+ expect(utils.getPath({ hash: true, search: true })).toBe('/test-page#section1?param=value')
165
+
166
+ // Test with search in hash
167
+ Object.defineProperty(window, 'location', {
168
+ value: {
169
+ pathname: '/test-page',
170
+ hash: '#section1?param=value',
171
+ search: '',
172
+ },
173
+ writable: true,
174
+ })
175
+ expect(utils.getPath({ hash: true, search: true })).toBe('/test-page#section1?param=value')
176
+ })
177
+
178
+ test('getUTM* functions should extract UTM parameters', () => {
179
+ // Arrange
180
+ Object.defineProperty(window, 'location', {
181
+ value: {
182
+ pathname: '/landing',
183
+ hash: '',
184
+ search: '?utm_source=google&utm_medium=cpc&utm_campaign=summer&utm_term=analytics&utm_content=ad1',
185
+ },
186
+ writable: true,
187
+ })
188
+
189
+ // Act & Assert
190
+ expect(utils.getUTMSource()).toBe('google')
191
+ expect(utils.getUTMMedium()).toBe('cpc')
192
+ expect(utils.getUTMCampaign()).toBe('summer')
193
+ expect(utils.getUTMTerm()).toBe('analytics')
194
+ expect(utils.getUTMContent()).toBe('ad1')
195
+
196
+ // Test with 'ref' and 'source' parameters as well
197
+ Object.defineProperty(window, 'location', {
198
+ value: {
199
+ pathname: '/landing',
200
+ hash: '',
201
+ search: '?ref=twitter',
202
+ },
203
+ writable: true,
204
+ })
205
+ expect(utils.getUTMSource()).toBe('twitter')
206
+
207
+ Object.defineProperty(window, 'location', {
208
+ value: {
209
+ pathname: '/landing',
210
+ hash: '',
211
+ search: '?source=newsletter',
212
+ },
213
+ writable: true,
214
+ })
215
+ expect(utils.getUTMSource()).toBe('newsletter')
216
+ })
217
+ })