@cccsaurora/howler-ui 2.19.0-dev.1266 → 2.19.0-dev.1276
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.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { render, waitFor } from '@testing-library/react';
|
|
2
|
+
import { act, render, screen, waitFor } from '@testing-library/react';
|
|
3
3
|
import { SocketContext } from '@cccsaurora/howler-ui/components/app/providers/SocketProvider';
|
|
4
4
|
import { createMockCase } from '@cccsaurora/howler-ui/tests/utils';
|
|
5
5
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
@@ -40,10 +40,10 @@ vi.mock('api', () => ({
|
|
|
40
40
|
}
|
|
41
41
|
}));
|
|
42
42
|
vi.mock('./detail/CaseDetails', () => ({
|
|
43
|
-
default: () => _jsx("div", { id: "case-details" })
|
|
43
|
+
default: ({ case: _case }) => _jsx("div", { id: "case-details", children: _case?.title })
|
|
44
44
|
}));
|
|
45
45
|
vi.mock('./detail/CaseSidebar', () => ({
|
|
46
|
-
default: () => _jsx("div", { id: "case-sidebar" })
|
|
46
|
+
default: ({ case: _case }) => _jsx("div", { id: "case-sidebar", children: _case?.title })
|
|
47
47
|
}));
|
|
48
48
|
// ---------------------------------------------------------------------------
|
|
49
49
|
// Import after mocks
|
|
@@ -130,4 +130,27 @@ describe('CaseViewer', () => {
|
|
|
130
130
|
expect(mockFetchViewers).toHaveBeenCalledWith('case-1');
|
|
131
131
|
});
|
|
132
132
|
});
|
|
133
|
+
it('propagates socket case updates to the sidebar and details', async () => {
|
|
134
|
+
const initialCase = createMockCase({ case_id: 'case-1', title: 'Original title' });
|
|
135
|
+
const updatedCase = createMockCase({ case_id: 'case-1', title: 'Updated title' });
|
|
136
|
+
mockDispatchApi.mockResolvedValue(initialCase);
|
|
137
|
+
render(_jsx(CaseViewer, {}), { wrapper: createWrapper() });
|
|
138
|
+
await waitFor(() => {
|
|
139
|
+
expect(mockAddListener).toHaveBeenCalledOnce();
|
|
140
|
+
});
|
|
141
|
+
await waitFor(() => {
|
|
142
|
+
expect(screen.getByTestId('case-sidebar')).toHaveTextContent('Original title');
|
|
143
|
+
});
|
|
144
|
+
act(() => {
|
|
145
|
+
mockAddListener.mock.calls[0][1]({
|
|
146
|
+
type: 'cases',
|
|
147
|
+
case: updatedCase,
|
|
148
|
+
error: false,
|
|
149
|
+
message: '',
|
|
150
|
+
status: 200
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
expect(screen.getByTestId('case-sidebar')).toHaveTextContent('Updated title');
|
|
154
|
+
expect(screen.getByTestId('case-details')).toHaveTextContent('Updated title');
|
|
155
|
+
});
|
|
133
156
|
});
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import api from '@cccsaurora/howler-ui/api';
|
|
2
2
|
import { SocketContext } from '@cccsaurora/howler-ui/components/app/providers/SocketProvider';
|
|
3
3
|
import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
|
|
4
|
-
import { useCallback, useContext, useEffect, useState } from 'react';
|
|
4
|
+
import { useCallback, useContext, useEffect, useId, useState } from 'react';
|
|
5
5
|
import { isCaseUpdate } from '@cccsaurora/howler-ui/utils/socketUtils';
|
|
6
6
|
const useCase = ({ caseId, case: providedCase }) => {
|
|
7
7
|
const { dispatchApi } = useMyApi();
|
|
8
8
|
const { addListener, removeListener } = useContext(SocketContext);
|
|
9
|
+
const listenerId = useId();
|
|
9
10
|
const [loading, setLoading] = useState(false);
|
|
10
11
|
const [missing, setMissing] = useState(false);
|
|
11
12
|
const [_case, setCase] = useState(providedCase);
|
|
@@ -27,7 +28,7 @@ const useCase = ({ caseId, case: providedCase }) => {
|
|
|
27
28
|
if (!activeCaseId) {
|
|
28
29
|
return;
|
|
29
30
|
}
|
|
30
|
-
const listenerKey = `case-update-${activeCaseId}`;
|
|
31
|
+
const listenerKey = `case-update-${activeCaseId}-${listenerId}`;
|
|
31
32
|
addListener(listenerKey, data => {
|
|
32
33
|
if (isCaseUpdate(data) && data.case.case_id === activeCaseId) {
|
|
33
34
|
setCase(data.case);
|
|
@@ -36,7 +37,7 @@ const useCase = ({ caseId, case: providedCase }) => {
|
|
|
36
37
|
return () => {
|
|
37
38
|
removeListener(listenerKey);
|
|
38
39
|
};
|
|
39
|
-
}, [activeCaseId, addListener, removeListener]);
|
|
40
|
+
}, [activeCaseId, addListener, listenerId, removeListener]);
|
|
40
41
|
const update = useCallback(async (_updatedCase, publish = true) => {
|
|
41
42
|
if (!activeCaseId) {
|
|
42
43
|
return;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { act, renderHook, waitFor } from '@testing-library/react';
|
|
1
|
+
import { act, render, renderHook, screen, waitFor } from '@testing-library/react';
|
|
2
|
+
import { createElement } from 'react';
|
|
2
3
|
import { createMockCase } from '@cccsaurora/howler-ui/tests/utils';
|
|
3
4
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
4
5
|
// ---------------------------------------------------------------------------
|
|
@@ -47,6 +48,12 @@ import useCase from './useCase';
|
|
|
47
48
|
const renderUseCaseHook = (args) => {
|
|
48
49
|
return renderHook(() => useCase(args));
|
|
49
50
|
};
|
|
51
|
+
const CaseConsumers = ({ case: providedCase }) => {
|
|
52
|
+
const sidebarCase = useCase({ case: providedCase });
|
|
53
|
+
const dashboardCase = useCase({ case: providedCase });
|
|
54
|
+
const detailsCase = useCase({ case: providedCase });
|
|
55
|
+
return createElement('div', null, createElement('span', { id: 'sidebar-case-title' }, sidebarCase.case.title), createElement('span', { id: 'dashboard-case-title' }, dashboardCase.case.title), createElement('span', { id: 'details-case-title' }, detailsCase.case.title));
|
|
56
|
+
};
|
|
50
57
|
// ---------------------------------------------------------------------------
|
|
51
58
|
// Setup
|
|
52
59
|
// ---------------------------------------------------------------------------
|
|
@@ -78,10 +85,10 @@ describe('useCase', () => {
|
|
|
78
85
|
});
|
|
79
86
|
});
|
|
80
87
|
describe('socket listener', () => {
|
|
81
|
-
it('registers a listener keyed by case ID', () => {
|
|
88
|
+
it('registers a listener keyed by case ID and hook instance', () => {
|
|
82
89
|
const mockCase = createMockCase({ case_id: 'c3' });
|
|
83
90
|
renderUseCaseHook({ case: mockCase });
|
|
84
|
-
expect(mockAddListener).toHaveBeenCalledWith(
|
|
91
|
+
expect(mockAddListener).toHaveBeenCalledWith(expect.stringMatching(/^case-update-c3-/), expect.any(Function));
|
|
85
92
|
});
|
|
86
93
|
it('updates state when a matching case update is received', () => {
|
|
87
94
|
const mockCase = createMockCase({ case_id: 'c4', title: 'Original' });
|
|
@@ -135,7 +142,29 @@ describe('useCase', () => {
|
|
|
135
142
|
const mockCase = createMockCase({ case_id: 'c7' });
|
|
136
143
|
const { unmount } = renderUseCaseHook({ case: mockCase });
|
|
137
144
|
unmount();
|
|
138
|
-
expect(mockRemoveListener).toHaveBeenCalledWith(
|
|
145
|
+
expect(mockRemoveListener).toHaveBeenCalledWith(expect.stringMatching(/^case-update-c7-/));
|
|
146
|
+
});
|
|
147
|
+
it('updates every concurrent case consumer for the same case', () => {
|
|
148
|
+
const mockCase = createMockCase({ case_id: 'c8', title: 'Original' });
|
|
149
|
+
render(createElement(CaseConsumers, { case: mockCase }));
|
|
150
|
+
const listenerKeys = mockAddListener.mock.calls.map(([key]) => key);
|
|
151
|
+
expect(listenerKeys).toHaveLength(3);
|
|
152
|
+
expect([...new Set(listenerKeys)]).toHaveLength(3);
|
|
153
|
+
const updatedCase = createMockCase({ case_id: 'c8', title: 'Updated via socket' });
|
|
154
|
+
act(() => {
|
|
155
|
+
mockAddListener.mock.calls.forEach(([, listener]) => {
|
|
156
|
+
listener({
|
|
157
|
+
type: 'cases',
|
|
158
|
+
case: updatedCase,
|
|
159
|
+
error: false,
|
|
160
|
+
message: '',
|
|
161
|
+
status: 200
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
expect(screen.getByTestId('sidebar-case-title')).toHaveTextContent('Updated via socket');
|
|
166
|
+
expect(screen.getByTestId('dashboard-case-title')).toHaveTextContent('Updated via socket');
|
|
167
|
+
expect(screen.getByTestId('details-case-title')).toHaveTextContent('Updated via socket');
|
|
139
168
|
});
|
|
140
169
|
});
|
|
141
170
|
});
|