@furystack/websocket-api 13.1.10 → 13.1.12
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/CHANGELOG.md +12 -0
- package/esm/websocket-api.spec.js +33 -18
- package/esm/websocket-api.spec.js.map +1 -1
- package/esm/websocket-integration.spec.js +16 -3
- package/esm/websocket-integration.spec.js.map +1 -1
- package/package.json +5 -3
- package/src/websocket-api.spec.ts +46 -29
- package/src/websocket-integration.spec.ts +18 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [13.1.12] - 2026-02-26
|
|
4
|
+
|
|
5
|
+
### ⬆️ Dependencies
|
|
6
|
+
|
|
7
|
+
- Updated `@furystack/rest-service` dependency
|
|
8
|
+
|
|
9
|
+
## [13.1.11] - 2026-02-22
|
|
10
|
+
|
|
11
|
+
### ⬆️ Dependencies
|
|
12
|
+
|
|
13
|
+
- Updated `@furystack/core` dependency
|
|
14
|
+
|
|
3
15
|
## [13.1.10] - 2026-02-20
|
|
4
16
|
|
|
5
17
|
### ⬆️ Dependencies
|
|
@@ -7,23 +7,37 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
import { InMemoryStore, User, addStore } from '@furystack/core';
|
|
8
8
|
import { getPort } from '@furystack/core/port-generator';
|
|
9
9
|
import { Injectable, Injector } from '@furystack/inject';
|
|
10
|
+
import { getRepository } from '@furystack/repository';
|
|
10
11
|
import { DefaultSession } from '@furystack/rest-service';
|
|
12
|
+
import { PasswordCredential, PasswordResetToken, usePasswordPolicy } from '@furystack/security';
|
|
11
13
|
import { usingAsync } from '@furystack/utils';
|
|
12
14
|
import { describe, expect, it } from 'vitest';
|
|
13
15
|
import { WebSocket } from 'ws';
|
|
14
16
|
import { useWebsockets } from './helpers.js';
|
|
15
17
|
import { WebSocketApi } from './websocket-api.js';
|
|
18
|
+
const setupStoresAndDataSets = (injector) => {
|
|
19
|
+
addStore(injector, new InMemoryStore({ model: User, primaryKey: 'username' }))
|
|
20
|
+
.addStore(new InMemoryStore({ model: DefaultSession, primaryKey: 'sessionId' }))
|
|
21
|
+
.addStore(new InMemoryStore({ model: PasswordCredential, primaryKey: 'userName' }))
|
|
22
|
+
.addStore(new InMemoryStore({ model: PasswordResetToken, primaryKey: 'token' }));
|
|
23
|
+
const repo = getRepository(injector);
|
|
24
|
+
repo.createDataSet(User, 'username');
|
|
25
|
+
repo.createDataSet(DefaultSession, 'sessionId');
|
|
26
|
+
repo.createDataSet(PasswordCredential, 'userName');
|
|
27
|
+
repo.createDataSet(PasswordResetToken, 'token');
|
|
28
|
+
usePasswordPolicy(injector);
|
|
29
|
+
};
|
|
16
30
|
describe('WebSocketApi', () => {
|
|
17
31
|
it('Should be built', async () => {
|
|
18
32
|
await usingAsync(new Injector(), async (i) => {
|
|
19
|
-
|
|
33
|
+
setupStoresAndDataSets(i);
|
|
20
34
|
await useWebsockets(i, { port: getPort() });
|
|
21
35
|
expect(i.getInstance(WebSocketApi)).toBeInstanceOf(WebSocketApi);
|
|
22
36
|
});
|
|
23
37
|
});
|
|
24
38
|
it('Should be built with settings', async () => {
|
|
25
39
|
await usingAsync(new Injector(), async (i) => {
|
|
26
|
-
|
|
40
|
+
setupStoresAndDataSets(i);
|
|
27
41
|
await useWebsockets(i, { path: '/web-socket', port: getPort() });
|
|
28
42
|
expect(i.getInstance(WebSocketApi)).toBeInstanceOf(WebSocketApi);
|
|
29
43
|
});
|
|
@@ -31,21 +45,25 @@ describe('WebSocketApi', () => {
|
|
|
31
45
|
it('Should broadcast messages', async () => {
|
|
32
46
|
const port = getPort();
|
|
33
47
|
await usingAsync(new Injector(), async (i) => {
|
|
34
|
-
|
|
35
|
-
expect.assertions(5); // All 5 clients should receive the message
|
|
48
|
+
setupStoresAndDataSets(i);
|
|
36
49
|
await useWebsockets(i, { path: '/web-socket', port });
|
|
37
50
|
const api = i.getInstance(WebSocketApi);
|
|
38
|
-
await Promise.all([1, 2, 3, 4, 5].map(async () => {
|
|
51
|
+
const clients = await Promise.all([1, 2, 3, 4, 5].map(async () => {
|
|
39
52
|
const client = new WebSocket(`ws://localhost:${port}/web-socket`);
|
|
40
|
-
await new Promise((resolve) => client.once('open', () =>
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
53
|
+
await new Promise((resolve) => client.once('open', () => resolve()));
|
|
54
|
+
return client;
|
|
55
|
+
}));
|
|
56
|
+
const messagePromises = clients.map((client) => new Promise((resolve) => {
|
|
57
|
+
client.once('message', (data) => resolve(data.toString()));
|
|
58
|
+
}));
|
|
59
|
+
await api.broadcast(({ ws }) => {
|
|
60
|
+
ws.send('alma');
|
|
61
|
+
});
|
|
62
|
+
const messages = await Promise.all(messagePromises);
|
|
63
|
+
for (const msg of messages) {
|
|
64
|
+
expect(msg).toBe('alma');
|
|
65
|
+
}
|
|
66
|
+
await Promise.all(clients.map(async (client) => {
|
|
49
67
|
client.close();
|
|
50
68
|
await new Promise((resolve) => client.once('close', () => resolve()));
|
|
51
69
|
}));
|
|
@@ -54,8 +72,7 @@ describe('WebSocketApi', () => {
|
|
|
54
72
|
it('Should receive client messages', async () => {
|
|
55
73
|
const port = getPort();
|
|
56
74
|
await usingAsync(new Injector(), async (i) => {
|
|
57
|
-
|
|
58
|
-
expect.assertions(2); // The action may be invoked twice due to test isolation issues
|
|
75
|
+
setupStoresAndDataSets(i);
|
|
59
76
|
const data = { value: 'test-message-unique' };
|
|
60
77
|
let ExampleWsAction = class ExampleWsAction {
|
|
61
78
|
[Symbol.dispose]() {
|
|
@@ -75,7 +92,6 @@ describe('WebSocketApi', () => {
|
|
|
75
92
|
}
|
|
76
93
|
async execute(options) {
|
|
77
94
|
expect(JSON.parse(options.data.toString())).toEqual(data);
|
|
78
|
-
// Send a response back so the client knows the action completed
|
|
79
95
|
options.socket.send('done');
|
|
80
96
|
}
|
|
81
97
|
};
|
|
@@ -85,7 +101,6 @@ describe('WebSocketApi', () => {
|
|
|
85
101
|
await useWebsockets(i, { path: '/web-socket-test', port, actions: [ExampleWsAction] });
|
|
86
102
|
const client = new WebSocket(`ws://localhost:${port}/web-socket-test`);
|
|
87
103
|
await new Promise((resolve) => client.once('open', () => resolve()));
|
|
88
|
-
// Wait for the response from the server
|
|
89
104
|
const responsePromise = new Promise((resolve) => {
|
|
90
105
|
client.once('message', () => {
|
|
91
106
|
resolve();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websocket-api.spec.js","sourceRoot":"","sources":["../src/websocket-api.spec.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAA;AACxD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,SAAS,EAAa,MAAM,IAAI,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAE5C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD,
|
|
1
|
+
{"version":3,"file":"websocket-api.spec.js","sourceRoot":"","sources":["../src/websocket-api.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { addStore, InMemoryStore, StoreManager, User } from '@furystack/core';
|
|
1
|
+
import { addStore, InMemoryStore, StoreManager, User, useSystemIdentityContext } from '@furystack/core';
|
|
2
2
|
import { getPort } from '@furystack/core/port-generator';
|
|
3
3
|
import { Injector } from '@furystack/inject';
|
|
4
|
+
import { getDataSetFor, getRepository } from '@furystack/repository';
|
|
4
5
|
import { DefaultSession, HttpUserContext, ServerManager, useHttpAuthentication, useRestService, } from '@furystack/rest-service';
|
|
6
|
+
import { PasswordCredential, PasswordResetToken, usePasswordPolicy } from '@furystack/security';
|
|
5
7
|
import { usingAsync } from '@furystack/utils';
|
|
6
8
|
import { describe, expect, it, vi } from 'vitest';
|
|
7
9
|
import { WebSocket } from 'ws';
|
|
@@ -21,7 +23,16 @@ describe('WebSocket Integration tests', () => {
|
|
|
21
23
|
port,
|
|
22
24
|
hostName: host,
|
|
23
25
|
});
|
|
24
|
-
addStore(injector, new InMemoryStore({ model: User, primaryKey: 'username' }))
|
|
26
|
+
addStore(injector, new InMemoryStore({ model: User, primaryKey: 'username' }))
|
|
27
|
+
.addStore(new InMemoryStore({ model: DefaultSession, primaryKey: 'sessionId' }))
|
|
28
|
+
.addStore(new InMemoryStore({ model: PasswordCredential, primaryKey: 'userName' }))
|
|
29
|
+
.addStore(new InMemoryStore({ model: PasswordResetToken, primaryKey: 'token' }));
|
|
30
|
+
const repo = getRepository(injector);
|
|
31
|
+
repo.createDataSet(User, 'username');
|
|
32
|
+
repo.createDataSet(DefaultSession, 'sessionId');
|
|
33
|
+
repo.createDataSet(PasswordCredential, 'userName');
|
|
34
|
+
repo.createDataSet(PasswordResetToken, 'token');
|
|
35
|
+
usePasswordPolicy(injector);
|
|
25
36
|
useHttpAuthentication(injector, {});
|
|
26
37
|
await useWebsockets(injector, { actions: [WhoAmI], path, port, host });
|
|
27
38
|
const client = await new Promise((resolve, reject) => {
|
|
@@ -90,7 +101,9 @@ describe('WebSocket Integration tests', () => {
|
|
|
90
101
|
});
|
|
91
102
|
const whoAmIResult = await getWhoAmIResult(authenticatedClient);
|
|
92
103
|
expect(whoAmIResult.currentUser).toEqual(testUser);
|
|
93
|
-
|
|
104
|
+
const systemInjector = useSystemIdentityContext({ injector, username: 'test' });
|
|
105
|
+
const userDataSet = getDataSetFor(systemInjector, User, 'username');
|
|
106
|
+
await userDataSet.update(systemInjector, testUser.username, { ...testUser, roles: ['newFancyRole'] });
|
|
94
107
|
const updatedWhoAmIResult = await getWhoAmIResult(authenticatedClient);
|
|
95
108
|
expect(updatedWhoAmIResult.currentUser.roles).toEqual(['newFancyRole']);
|
|
96
109
|
await userCtx.cookieLogout({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websocket-integration.spec.js","sourceRoot":"","sources":["../src/websocket-integration.spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"websocket-integration.spec.js","sourceRoot":"","sources":["../src/websocket-integration.spec.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@furystack/websocket-api",
|
|
3
|
-
"version": "13.1.
|
|
3
|
+
"version": "13.1.12",
|
|
4
4
|
"description": "WebSocket API implementation for FuryStack",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -37,13 +37,15 @@
|
|
|
37
37
|
},
|
|
38
38
|
"homepage": "https://github.com/furystack/furystack",
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@furystack/core": "^15.1
|
|
40
|
+
"@furystack/core": "^15.2.1",
|
|
41
41
|
"@furystack/inject": "^12.0.30",
|
|
42
|
-
"@furystack/rest-service": "^
|
|
42
|
+
"@furystack/rest-service": "^12.0.0",
|
|
43
43
|
"@furystack/utils": "^8.1.10",
|
|
44
44
|
"ws": "^8.19.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
+
"@furystack/repository": "^10.1.2",
|
|
48
|
+
"@furystack/security": "^7.0.0",
|
|
47
49
|
"@types/ws": "^8.18.1",
|
|
48
50
|
"typescript": "^5.9.3",
|
|
49
51
|
"vitest": "^4.0.18"
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { InMemoryStore, User, addStore } from '@furystack/core'
|
|
2
2
|
import { getPort } from '@furystack/core/port-generator'
|
|
3
3
|
import { Injectable, Injector } from '@furystack/inject'
|
|
4
|
+
import { getRepository } from '@furystack/repository'
|
|
4
5
|
import { DefaultSession } from '@furystack/rest-service'
|
|
6
|
+
import { PasswordCredential, PasswordResetToken, usePasswordPolicy } from '@furystack/security'
|
|
5
7
|
import { usingAsync } from '@furystack/utils'
|
|
6
8
|
import { describe, expect, it } from 'vitest'
|
|
7
9
|
import { WebSocket, type Data } from 'ws'
|
|
@@ -9,22 +11,32 @@ import { useWebsockets } from './helpers.js'
|
|
|
9
11
|
import type { WebSocketAction } from './models/websocket-action.js'
|
|
10
12
|
import { WebSocketApi } from './websocket-api.js'
|
|
11
13
|
|
|
14
|
+
const setupStoresAndDataSets = (injector: Injector) => {
|
|
15
|
+
addStore(injector, new InMemoryStore({ model: User, primaryKey: 'username' }))
|
|
16
|
+
.addStore(new InMemoryStore({ model: DefaultSession, primaryKey: 'sessionId' }))
|
|
17
|
+
.addStore(new InMemoryStore({ model: PasswordCredential, primaryKey: 'userName' }))
|
|
18
|
+
.addStore(new InMemoryStore({ model: PasswordResetToken, primaryKey: 'token' }))
|
|
19
|
+
|
|
20
|
+
const repo = getRepository(injector)
|
|
21
|
+
repo.createDataSet(User, 'username')
|
|
22
|
+
repo.createDataSet(DefaultSession, 'sessionId')
|
|
23
|
+
repo.createDataSet(PasswordCredential, 'userName')
|
|
24
|
+
repo.createDataSet(PasswordResetToken, 'token')
|
|
25
|
+
|
|
26
|
+
usePasswordPolicy(injector)
|
|
27
|
+
}
|
|
28
|
+
|
|
12
29
|
describe('WebSocketApi', () => {
|
|
13
30
|
it('Should be built', async () => {
|
|
14
31
|
await usingAsync(new Injector(), async (i) => {
|
|
15
|
-
|
|
16
|
-
new InMemoryStore({ model: DefaultSession, primaryKey: 'sessionId' }),
|
|
17
|
-
)
|
|
32
|
+
setupStoresAndDataSets(i)
|
|
18
33
|
await useWebsockets(i, { port: getPort() })
|
|
19
34
|
expect(i.getInstance(WebSocketApi)).toBeInstanceOf(WebSocketApi)
|
|
20
35
|
})
|
|
21
36
|
})
|
|
22
37
|
it('Should be built with settings', async () => {
|
|
23
38
|
await usingAsync(new Injector(), async (i) => {
|
|
24
|
-
|
|
25
|
-
new InMemoryStore({ model: DefaultSession, primaryKey: 'sessionId' }),
|
|
26
|
-
)
|
|
27
|
-
|
|
39
|
+
setupStoresAndDataSets(i)
|
|
28
40
|
await useWebsockets(i, { path: '/web-socket', port: getPort() })
|
|
29
41
|
expect(i.getInstance(WebSocketApi)).toBeInstanceOf(WebSocketApi)
|
|
30
42
|
})
|
|
@@ -33,27 +45,37 @@ describe('WebSocketApi', () => {
|
|
|
33
45
|
it('Should broadcast messages', async () => {
|
|
34
46
|
const port = getPort()
|
|
35
47
|
await usingAsync(new Injector(), async (i) => {
|
|
36
|
-
|
|
37
|
-
new InMemoryStore({ model: DefaultSession, primaryKey: 'sessionId' }),
|
|
38
|
-
)
|
|
48
|
+
setupStoresAndDataSets(i)
|
|
39
49
|
|
|
40
|
-
expect.assertions(5) // All 5 clients should receive the message
|
|
41
50
|
await useWebsockets(i, { path: '/web-socket', port })
|
|
42
51
|
const api = i.getInstance(WebSocketApi)
|
|
43
|
-
|
|
52
|
+
|
|
53
|
+
const clients = await Promise.all(
|
|
44
54
|
[1, 2, 3, 4, 5].map(async () => {
|
|
45
55
|
const client = new WebSocket(`ws://localhost:${port}/web-socket`)
|
|
46
|
-
await new Promise<void>((resolve) =>
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
await new Promise<void>((resolve) => client.once('open', () => resolve()))
|
|
57
|
+
return client
|
|
58
|
+
}),
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
const messagePromises = clients.map(
|
|
62
|
+
(client) =>
|
|
63
|
+
new Promise<string>((resolve) => {
|
|
64
|
+
client.once('message', (data) => resolve((data as Buffer).toString()))
|
|
65
|
+
}),
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
await api.broadcast(({ ws }) => {
|
|
69
|
+
ws.send('alma')
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
const messages = await Promise.all(messagePromises)
|
|
73
|
+
for (const msg of messages) {
|
|
74
|
+
expect(msg).toBe('alma')
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
await Promise.all(
|
|
78
|
+
clients.map(async (client) => {
|
|
57
79
|
client.close()
|
|
58
80
|
await new Promise<void>((resolve) => client.once('close', () => resolve()))
|
|
59
81
|
}),
|
|
@@ -64,11 +86,8 @@ describe('WebSocketApi', () => {
|
|
|
64
86
|
it('Should receive client messages', async () => {
|
|
65
87
|
const port = getPort()
|
|
66
88
|
await usingAsync(new Injector(), async (i) => {
|
|
67
|
-
|
|
68
|
-
new InMemoryStore({ model: DefaultSession, primaryKey: 'sessionId' }),
|
|
69
|
-
)
|
|
89
|
+
setupStoresAndDataSets(i)
|
|
70
90
|
|
|
71
|
-
expect.assertions(2) // The action may be invoked twice due to test isolation issues
|
|
72
91
|
const data = { value: 'test-message-unique' }
|
|
73
92
|
@Injectable()
|
|
74
93
|
class ExampleWsAction implements WebSocketAction {
|
|
@@ -91,7 +110,6 @@ describe('WebSocketApi', () => {
|
|
|
91
110
|
|
|
92
111
|
public async execute(options: { data: Data; socket: WebSocket }) {
|
|
93
112
|
expect(JSON.parse((options.data as Buffer).toString())).toEqual(data)
|
|
94
|
-
// Send a response back so the client knows the action completed
|
|
95
113
|
options.socket.send('done')
|
|
96
114
|
}
|
|
97
115
|
}
|
|
@@ -100,7 +118,6 @@ describe('WebSocketApi', () => {
|
|
|
100
118
|
const client = new WebSocket(`ws://localhost:${port}/web-socket-test`)
|
|
101
119
|
await new Promise<void>((resolve) => client.once('open', () => resolve()))
|
|
102
120
|
|
|
103
|
-
// Wait for the response from the server
|
|
104
121
|
const responsePromise = new Promise<void>((resolve) => {
|
|
105
122
|
client.once('message', () => {
|
|
106
123
|
resolve()
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { addStore, InMemoryStore, StoreManager, User } from '@furystack/core'
|
|
1
|
+
import { addStore, InMemoryStore, StoreManager, User, useSystemIdentityContext } from '@furystack/core'
|
|
2
2
|
import { getPort } from '@furystack/core/port-generator'
|
|
3
3
|
import { Injector } from '@furystack/inject'
|
|
4
|
+
import { getDataSetFor, getRepository } from '@furystack/repository'
|
|
4
5
|
import {
|
|
5
6
|
DefaultSession,
|
|
6
7
|
HttpUserContext,
|
|
@@ -8,6 +9,7 @@ import {
|
|
|
8
9
|
useHttpAuthentication,
|
|
9
10
|
useRestService,
|
|
10
11
|
} from '@furystack/rest-service'
|
|
12
|
+
import { PasswordCredential, PasswordResetToken, usePasswordPolicy } from '@furystack/security'
|
|
11
13
|
import { usingAsync } from '@furystack/utils'
|
|
12
14
|
import { describe, expect, it, vi } from 'vitest'
|
|
13
15
|
import { WebSocket } from 'ws'
|
|
@@ -30,9 +32,18 @@ describe('WebSocket Integration tests', () => {
|
|
|
30
32
|
port,
|
|
31
33
|
hostName: host,
|
|
32
34
|
})
|
|
33
|
-
addStore(injector, new InMemoryStore({ model: User, primaryKey: 'username' }))
|
|
34
|
-
new InMemoryStore({ model: DefaultSession, primaryKey: 'sessionId' })
|
|
35
|
-
|
|
35
|
+
addStore(injector, new InMemoryStore({ model: User, primaryKey: 'username' }))
|
|
36
|
+
.addStore(new InMemoryStore({ model: DefaultSession, primaryKey: 'sessionId' }))
|
|
37
|
+
.addStore(new InMemoryStore({ model: PasswordCredential, primaryKey: 'userName' }))
|
|
38
|
+
.addStore(new InMemoryStore({ model: PasswordResetToken, primaryKey: 'token' }))
|
|
39
|
+
|
|
40
|
+
const repo = getRepository(injector)
|
|
41
|
+
repo.createDataSet(User, 'username')
|
|
42
|
+
repo.createDataSet(DefaultSession, 'sessionId')
|
|
43
|
+
repo.createDataSet(PasswordCredential, 'userName')
|
|
44
|
+
repo.createDataSet(PasswordResetToken, 'token')
|
|
45
|
+
|
|
46
|
+
usePasswordPolicy(injector)
|
|
36
47
|
useHttpAuthentication(injector, {})
|
|
37
48
|
await useWebsockets(injector, { actions: [WhoAmI], path, port, host })
|
|
38
49
|
|
|
@@ -111,7 +122,9 @@ describe('WebSocket Integration tests', () => {
|
|
|
111
122
|
const whoAmIResult = await getWhoAmIResult(authenticatedClient)
|
|
112
123
|
expect(whoAmIResult.currentUser).toEqual(testUser)
|
|
113
124
|
|
|
114
|
-
|
|
125
|
+
const systemInjector = useSystemIdentityContext({ injector, username: 'test' })
|
|
126
|
+
const userDataSet = getDataSetFor(systemInjector, User, 'username')
|
|
127
|
+
await userDataSet.update(systemInjector, testUser.username, { ...testUser, roles: ['newFancyRole'] })
|
|
115
128
|
|
|
116
129
|
const updatedWhoAmIResult = await getWhoAmIResult(authenticatedClient)
|
|
117
130
|
expect(updatedWhoAmIResult.currentUser.roles).toEqual(['newFancyRole'])
|