Skip to content

Commit fcfe031

Browse files
authored
feat: merge pull request #381 from cattr-app/coderabbit/add-pull-request-tests/6e28fc68
Add unit tests for role service request and cancellation behavior
2 parents 363518d + fa0ca2f commit fcfe031

1 file changed

Lines changed: 107 additions & 0 deletions

File tree

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import assert from 'node:assert/strict';
2+
import { registerHooks } from 'node:module';
3+
import { test } from 'node:test';
4+
import axios from 'axios';
5+
6+
// Run with the repository's Node 24 runtime:
7+
// node --test tests/Unit/Frontend/role.service.test.mjs
8+
// Resolve the Webpack alias without building the frontend or changing application imports.
9+
const aliasHook = registerHooks({
10+
resolve(specifier, context, nextResolve) {
11+
if (specifier === '@/services/resource.service') {
12+
return nextResolve(
13+
new URL('../../../resources/frontend/core/services/resource.service.js', import.meta.url).href,
14+
context,
15+
);
16+
}
17+
18+
return nextResolve(specifier, context);
19+
},
20+
});
21+
22+
let RoleService;
23+
try {
24+
({ default: RoleService } = await import('../../../resources/frontend/core/services/resource/role.service.js'));
25+
} finally {
26+
aliasHook.deregister();
27+
}
28+
29+
test('getAll requests the role list once and excludes it from navigation cancellation', t => {
30+
const request = Promise.resolve({ data: { data: [] } });
31+
const get = t.mock.method(axios, 'get', () => request);
32+
33+
const result = new RoleService().getAll();
34+
35+
assert.equal(get.mock.callCount(), 1);
36+
assert.deepEqual(get.mock.calls[0].arguments, ['roles/list', { ignoreCancel: true }]);
37+
assert.strictEqual(result, request, 'the caller must receive the original Axios promise');
38+
});
39+
40+
for (const [name, roles] of [
41+
[
42+
'populated',
43+
[
44+
{ id: 1, name: 'Admin' },
45+
{ id: 2, name: 'User' },
46+
],
47+
],
48+
['empty', []],
49+
]) {
50+
test(`getAll preserves the complete Axios response for a ${name} role list`, async t => {
51+
const response = {
52+
data: { data: roles },
53+
status: 200,
54+
statusText: 'OK',
55+
headers: { 'content-type': 'application/json' },
56+
};
57+
t.mock.method(axios, 'get', () => Promise.resolve(response));
58+
59+
assert.strictEqual(await new RoleService().getAll(), response);
60+
});
61+
}
62+
63+
for (const [name, error] of [
64+
[
65+
'forbidden responses',
66+
new axios.AxiosError('Forbidden', 'ERR_BAD_REQUEST', undefined, undefined, { status: 403 }),
67+
],
68+
[
69+
'server failures',
70+
new axios.AxiosError('Server error', 'ERR_BAD_RESPONSE', undefined, undefined, { status: 500 }),
71+
],
72+
['network failures', new axios.AxiosError('Network Error', 'ERR_NETWORK')],
73+
['explicit cancellation', new axios.CanceledError('Request canceled')],
74+
]) {
75+
test(`getAll propagates ${name} unchanged despite ignoring navigation cancellation`, async t => {
76+
t.mock.method(axios, 'get', () => Promise.reject(error));
77+
78+
await assert.rejects(
79+
() => new RoleService().getAll(),
80+
actual => actual === error,
81+
);
82+
});
83+
}
84+
85+
test('getAll protects every request when called again while a role request is pending', async t => {
86+
const firstRequest = Promise.withResolvers();
87+
const secondRequest = Promise.withResolvers();
88+
const responses = [{ data: { data: [{ id: 1, name: 'Admin' }] } }, { data: { data: [] } }];
89+
const get = t.mock.method(axios, 'get', () => firstRequest.promise);
90+
get.mock.mockImplementationOnce(() => secondRequest.promise, 1);
91+
const service = new RoleService();
92+
93+
const first = service.getAll();
94+
const second = service.getAll();
95+
96+
assert.equal(get.mock.callCount(), 2);
97+
for (const call of get.mock.calls) {
98+
assert.deepEqual(call.arguments, ['roles/list', { ignoreCancel: true }]);
99+
}
100+
assert.strictEqual(first, firstRequest.promise);
101+
assert.strictEqual(second, secondRequest.promise);
102+
103+
secondRequest.resolve(responses[1]);
104+
assert.strictEqual(await second, responses[1]);
105+
firstRequest.resolve(responses[0]);
106+
assert.strictEqual(await first, responses[0]);
107+
});

0 commit comments

Comments
 (0)