gameglue 1.1.1 → 1.1.2
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.
- package/babel.config.js +5 -0
- package/coverage/auth.js.html +526 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +176 -0
- package/coverage/index.js.html +310 -0
- package/coverage/lcov-report/auth.js.html +526 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +176 -0
- package/coverage/lcov-report/index.js.html +310 -0
- package/coverage/lcov-report/listener.js.html +529 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov-report/user.js.html +118 -0
- package/coverage/lcov-report/utils.js.html +118 -0
- package/coverage/lcov.info +391 -0
- package/coverage/listener.js.html +529 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/coverage/user.js.html +118 -0
- package/coverage/utils.js.html +118 -0
- package/jest.config.js +30 -0
- package/package.json +11 -3
- package/src/auth.spec.js +391 -0
- package/src/listener.spec.js +299 -0
- package/src/test/fixtures.js +106 -0
- package/src/test/setup.js +50 -0
- package/src/utils.spec.js +64 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// Test fixtures for GameGlueJS SDK
|
|
2
|
+
|
|
3
|
+
// Helper to create a JWT with custom payload
|
|
4
|
+
function createMockJwt(payload, expiresInSeconds = 3600) {
|
|
5
|
+
const header = { alg: 'RS256', typ: 'JWT' };
|
|
6
|
+
const now = Math.floor(Date.now() / 1000);
|
|
7
|
+
const defaultPayload = {
|
|
8
|
+
sub: 'user-123',
|
|
9
|
+
exp: now + expiresInSeconds,
|
|
10
|
+
iat: now,
|
|
11
|
+
aud: 'gameglue-client',
|
|
12
|
+
iss: 'https://auth.gameglue.gg/realms/GameGlue',
|
|
13
|
+
scope: 'openid gg:broadcast msfs:read',
|
|
14
|
+
...payload
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const base64Header = Buffer.from(JSON.stringify(header)).toString('base64url');
|
|
18
|
+
const base64Payload = Buffer.from(JSON.stringify(defaultPayload)).toString('base64url');
|
|
19
|
+
// Fake signature (not cryptographically valid, but works for decoding tests)
|
|
20
|
+
const signature = 'fake_signature_for_testing';
|
|
21
|
+
|
|
22
|
+
return `${base64Header}.${base64Payload}.${signature}`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Valid access token (expires in 1 hour)
|
|
26
|
+
const validAccessToken = createMockJwt({ sub: 'user-123' }, 3600);
|
|
27
|
+
|
|
28
|
+
// Expired access token
|
|
29
|
+
const expiredAccessToken = createMockJwt({ sub: 'user-123' }, -100);
|
|
30
|
+
|
|
31
|
+
// Valid refresh token
|
|
32
|
+
const validRefreshToken = createMockJwt({ sub: 'user-123', type: 'refresh' }, 86400);
|
|
33
|
+
|
|
34
|
+
// Mock user configuration
|
|
35
|
+
const mockConfig = {
|
|
36
|
+
clientId: 'test-client-id',
|
|
37
|
+
redirect_uri: 'http://localhost:3000/callback',
|
|
38
|
+
scopes: ['msfs:read', 'gg:broadcast']
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Mock listener configuration
|
|
42
|
+
const mockListenerConfig = {
|
|
43
|
+
gameId: 'msfs',
|
|
44
|
+
userId: 'user-123',
|
|
45
|
+
fields: ['altitude', 'airspeed', 'heading']
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// Mock socket instance
|
|
49
|
+
function createMockSocket() {
|
|
50
|
+
const eventHandlers = {};
|
|
51
|
+
const ioEventHandlers = {};
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
auth: { token: null },
|
|
55
|
+
connected: true,
|
|
56
|
+
on: jest.fn((event, handler) => {
|
|
57
|
+
eventHandlers[event] = handler;
|
|
58
|
+
}),
|
|
59
|
+
emit: jest.fn((event, data, callback) => {
|
|
60
|
+
// Simulate successful responses
|
|
61
|
+
if (callback) {
|
|
62
|
+
if (event === 'listen') {
|
|
63
|
+
callback(null, { status: 'success' });
|
|
64
|
+
} else if (event === 'listen-update') {
|
|
65
|
+
callback(null, { status: 'success' });
|
|
66
|
+
} else if (event === 'set') {
|
|
67
|
+
callback(null, { status: 'success' });
|
|
68
|
+
} else {
|
|
69
|
+
callback(null, { status: 'success' });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}),
|
|
73
|
+
timeout: jest.fn(function() {
|
|
74
|
+
return this;
|
|
75
|
+
}),
|
|
76
|
+
disconnect: jest.fn(),
|
|
77
|
+
io: {
|
|
78
|
+
on: jest.fn((event, handler) => {
|
|
79
|
+
ioEventHandlers[event] = handler;
|
|
80
|
+
})
|
|
81
|
+
},
|
|
82
|
+
// Helpers for tests to trigger events
|
|
83
|
+
_trigger: (event, data) => {
|
|
84
|
+
if (eventHandlers[event]) {
|
|
85
|
+
eventHandlers[event](data);
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
_triggerIo: (event, data) => {
|
|
89
|
+
if (ioEventHandlers[event]) {
|
|
90
|
+
ioEventHandlers[event](data);
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
_getHandler: (event) => eventHandlers[event],
|
|
94
|
+
_getIoHandler: (event) => ioEventHandlers[event]
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = {
|
|
99
|
+
createMockJwt,
|
|
100
|
+
validAccessToken,
|
|
101
|
+
expiredAccessToken,
|
|
102
|
+
validRefreshToken,
|
|
103
|
+
mockConfig,
|
|
104
|
+
mockListenerConfig,
|
|
105
|
+
createMockSocket
|
|
106
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Jest setup file for GameGlueJS SDK
|
|
2
|
+
|
|
3
|
+
// Create a proper localStorage mock with internal store
|
|
4
|
+
let localStore = {};
|
|
5
|
+
|
|
6
|
+
const localStorageMock = {
|
|
7
|
+
getItem: jest.fn((key) => localStore[key] || null),
|
|
8
|
+
setItem: jest.fn((key, value) => {
|
|
9
|
+
localStore[key] = String(value);
|
|
10
|
+
}),
|
|
11
|
+
removeItem: jest.fn((key) => {
|
|
12
|
+
delete localStore[key];
|
|
13
|
+
}),
|
|
14
|
+
clear: jest.fn(() => {
|
|
15
|
+
localStore = {};
|
|
16
|
+
}),
|
|
17
|
+
get length() {
|
|
18
|
+
return Object.keys(localStore).length;
|
|
19
|
+
},
|
|
20
|
+
key: jest.fn((i) => Object.keys(localStore)[i] || null)
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Override localStorage on window (jsdom provides window)
|
|
24
|
+
Object.defineProperty(window, 'localStorage', {
|
|
25
|
+
value: localStorageMock,
|
|
26
|
+
writable: true
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Also set on global for Node environment
|
|
30
|
+
Object.defineProperty(global, 'localStorage', {
|
|
31
|
+
value: localStorageMock,
|
|
32
|
+
writable: true
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Mock window.history.pushState
|
|
36
|
+
window.history.pushState = jest.fn();
|
|
37
|
+
|
|
38
|
+
// Reset mocks and store before each test
|
|
39
|
+
beforeEach(() => {
|
|
40
|
+
localStore = {};
|
|
41
|
+
localStorageMock.getItem.mockClear();
|
|
42
|
+
localStorageMock.setItem.mockClear();
|
|
43
|
+
localStorageMock.removeItem.mockClear();
|
|
44
|
+
localStorageMock.clear.mockClear();
|
|
45
|
+
|
|
46
|
+
// Reset window.location.hash using the proper jsdom approach
|
|
47
|
+
window.location.hash = '';
|
|
48
|
+
|
|
49
|
+
jest.clearAllMocks();
|
|
50
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
const { storage, isBrowser } = require('./utils');
|
|
2
|
+
|
|
3
|
+
describe('utils', () => {
|
|
4
|
+
describe('isBrowser', () => {
|
|
5
|
+
it('should return false in Node.js/Jest environment', () => {
|
|
6
|
+
// In Jest (Node.js), process is defined, so isBrowser returns false
|
|
7
|
+
const result = isBrowser();
|
|
8
|
+
expect(result).toBe(false);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should return boolean', () => {
|
|
12
|
+
const result = isBrowser();
|
|
13
|
+
expect(typeof result).toBe('boolean');
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('storage', () => {
|
|
18
|
+
describe('in Node.js environment (isBrowser = false)', () => {
|
|
19
|
+
// In Jest, isBrowser() returns false, so storage uses in-memory map
|
|
20
|
+
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
// Clear storage by setting and getting values
|
|
23
|
+
// The in-memory store persists between tests within a module
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe('set', () => {
|
|
27
|
+
it('should store a value', () => {
|
|
28
|
+
storage.set('test-key', 'test-value');
|
|
29
|
+
const result = storage.get('test-key');
|
|
30
|
+
expect(result).toBe('test-value');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should handle various value types', () => {
|
|
34
|
+
storage.set('string-key', 'string-value');
|
|
35
|
+
storage.set('number-key', '12345');
|
|
36
|
+
storage.set('token-key', 'eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ0ZXN0In0.sig');
|
|
37
|
+
|
|
38
|
+
expect(storage.get('string-key')).toBe('string-value');
|
|
39
|
+
expect(storage.get('number-key')).toBe('12345');
|
|
40
|
+
expect(storage.get('token-key')).toBe('eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ0ZXN0In0.sig');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should overwrite existing values', () => {
|
|
44
|
+
storage.set('overwrite-key', 'initial');
|
|
45
|
+
storage.set('overwrite-key', 'updated');
|
|
46
|
+
expect(storage.get('overwrite-key')).toBe('updated');
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe('get', () => {
|
|
51
|
+
it('should retrieve a stored value', () => {
|
|
52
|
+
storage.set('retrieve-key', 'retrieve-value');
|
|
53
|
+
const result = storage.get('retrieve-key');
|
|
54
|
+
expect(result).toBe('retrieve-value');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should return undefined for non-existent keys', () => {
|
|
58
|
+
const result = storage.get('definitely-non-existent-key-' + Date.now());
|
|
59
|
+
expect(result).toBeUndefined();
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
});
|