Skip to content

Commit 32424a8

Browse files
authored
Merge pull request #5 from flow-build/test/DAT-393
Test/DAT-393
2 parents 8b2de15 + 13191f8 commit 32424a8

File tree

11 files changed

+183
-26
lines changed

11 files changed

+183
-26
lines changed

.github/workflows/main.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
strategy:
99
matrix:
1010
node: ['18.x']
11-
os: [ubuntu-latest, windows-latest, macOS-latest]
11+
os: [ubuntu-latest, macOS-latest]
1212

1313
steps:
1414
- name: Checkout repo
@@ -29,5 +29,8 @@ jobs:
2929
- name: Lint
3030
run: yarn lint
3131

32+
- name: Test
33+
run: yarn test
34+
3235
- name: Build
3336
run: yarn build

.github/workflows/size.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ jobs:
77
strategy:
88
matrix:
99
node: ['18.x']
10-
os: [ubuntu-latest, windows-latest, macOS-latest]
10+
os: [ubuntu-latest, macOS-latest]
1111
env:
1212
CI_JOB_NUMBER: 1
1313
steps:

__tests__/WorkflowManager.test.tsx

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import React, { PropsWithChildren } from 'react';
2+
3+
import { renderHook, act, waitFor } from '@testing-library/react';
4+
5+
import {
6+
WorkflowManager,
7+
WorkflowManagerConfig,
8+
useMqtt,
9+
useSubscribe,
10+
useUnsubscribe,
11+
} from '../src';
12+
import { store } from './store';
13+
import { MqttClientExtended } from './types';
14+
15+
const props = {
16+
brokerUrl: 'ws://broker.mqttdashboard.com:8000/mqtt',
17+
options: {
18+
clientId: `clientId-${Math.random().toString(16).substring(2, 8)}`,
19+
reconnectPeriod: 1000,
20+
},
21+
};
22+
23+
let wrapper: React.FC<PropsWithChildren>;
24+
25+
describe('WorkflowManager component', () => {
26+
beforeEach(() => {
27+
WorkflowManagerConfig.setStore(store);
28+
29+
wrapper = ({ children }) => (
30+
<WorkflowManager {...props}>{children}</WorkflowManager>
31+
);
32+
});
33+
34+
it('should connect with mqtt', async () => {
35+
const { result } = renderHook(() => useMqtt(), { wrapper });
36+
37+
await waitFor(
38+
() => {
39+
const status = result.current?.status;
40+
return expect(status === 'connected').toBe(true);
41+
},
42+
{ timeout: 2000 },
43+
);
44+
45+
expect(result.current?.status).toBe('connected');
46+
47+
await act(async () => {
48+
result.current.client?.end();
49+
});
50+
});
51+
52+
it('should not connect with mqtt: invalid broker url', async () => {
53+
const { result } = renderHook(() => useMqtt(), {
54+
wrapper: ({ children }) => (
55+
<WorkflowManager
56+
brokerUrl="ws://broker.mqttdashboard@@.com:8000/mqtt"
57+
options={{ ...props.options, connectTimeout: 2000 }}
58+
>
59+
{children}
60+
</WorkflowManager>
61+
),
62+
});
63+
64+
await waitFor(
65+
() => {
66+
const status = result.current?.status;
67+
68+
return expect(status === 'reconnecting').toBe(true);
69+
},
70+
{ timeout: 2000 },
71+
);
72+
73+
expect(result.current?.status).toBe('reconnecting');
74+
75+
await act(async () => {
76+
result.current.client?.end();
77+
});
78+
});
79+
80+
it('should subscribe to topics', async () => {
81+
const { result: resultSub } = renderHook(() => useSubscribe(), { wrapper });
82+
const { result: resultMqtt } = renderHook(() => useMqtt(), { wrapper });
83+
84+
const subscribe = resultSub.current;
85+
const client = resultMqtt.current.client as MqttClientExtended;
86+
87+
await waitFor(
88+
() => {
89+
const status = resultMqtt.current?.status;
90+
return expect(status === 'connected').toBe(true);
91+
},
92+
{ timeout: 2000 },
93+
);
94+
95+
expect(resultMqtt.current.status).toBe('connected');
96+
97+
const topic = 'workflowManager/test/1';
98+
99+
subscribe(topic);
100+
101+
const lastMessageId = client?.getLastMessageId();
102+
const subscribedTopics = client?.messageIdToTopic[lastMessageId];
103+
104+
expect(subscribedTopics).toContain(topic);
105+
106+
await act(async () => {
107+
client?.end();
108+
});
109+
});
110+
111+
it('should unsubscribe from topics', async () => {
112+
const { result: resultSub } = renderHook(() => useSubscribe(), { wrapper });
113+
const { result: resultUnsub } = renderHook(() => useUnsubscribe(), {
114+
wrapper,
115+
});
116+
const { result: resultMqtt } = renderHook(() => useMqtt(), { wrapper });
117+
118+
const subscribe = resultSub.current;
119+
const unsubscribe = resultUnsub.current;
120+
const client = resultMqtt.current.client as MqttClientExtended;
121+
122+
await waitFor(
123+
() => {
124+
const status = resultMqtt.current?.status;
125+
return expect(status === 'connected').toBe(true);
126+
},
127+
{ timeout: 2000 },
128+
);
129+
130+
expect(resultMqtt.current.status).toBe('connected');
131+
132+
const topic = 'workflowManager/test/1';
133+
134+
subscribe(topic);
135+
136+
const lastMessageId = client?.getLastMessageId();
137+
const subscribedTopics = client?.messageIdToTopic[lastMessageId];
138+
139+
expect(subscribedTopics).toContain(topic);
140+
141+
unsubscribe(topic);
142+
143+
const newLastMessageId = client?.getLastMessageId();
144+
const newSubscribedTopics =
145+
client?.messageIdToTopic[newLastMessageId] || [];
146+
147+
expect(newSubscribedTopics).not.toContain(topic);
148+
149+
await act(async () => {
150+
client?.end();
151+
});
152+
});
153+
});

__tests__/store.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { configureStore } from '@reduxjs/toolkit';
2+
3+
import { workflowManagerReducer } from '../src';
4+
5+
export const store = configureStore({
6+
reducer: { workflowManagerReducer },
7+
});

__tests__/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { MqttClient } from 'mqtt-browser';
2+
export interface MqttClientExtended extends MqttClient {
3+
messageIdToTopic: Record<string, string[]>;
4+
}

jest.config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
export default {
22
clearMocks: true,
33
preset: 'ts-jest',
4-
roots: ['<rootDir>/src'],
4+
roots: ['<rootDir>/__tests__'],
55
testEnvironment: 'jsdom',
6-
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$',
6+
testRegex: 'WorkflowManager.test.tsx',
77
transform: {
88
'^.+\\.tsx?$': 'ts-jest',
99
},

src/WorkflowManager.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export const WorkflowManager: FC<WorkflowManagerProps> = ({
2323
const mqttInstance = connect(brokerUrl, options);
2424

2525
mqttInstance.on('connect', () => {
26+
if (status !== 'connected') setStatus('connected');
2627
setStatus('connected');
2728
});
2829

@@ -31,15 +32,16 @@ export const WorkflowManager: FC<WorkflowManagerProps> = ({
3132
});
3233

3334
mqttInstance.on('offline', () => {
34-
setStatus('offline');
35+
if (status !== 'offline') setStatus('offline');
3536
});
3637

3738
mqttInstance.on('error', () => {
38-
setStatus('error');
39+
if (status !== 'error') setStatus('error');
3940
invariant(false, ERROR_MESSAGES.ERROR_OCURRED);
4041
});
4142

4243
mqttInstance.on('reconnect', () => {
44+
if (status !== 'reconnecting') setStatus('reconnecting');
4345
setStatus('reconnecting');
4446
});
4547

@@ -51,7 +53,7 @@ export const WorkflowManager: FC<WorkflowManagerProps> = ({
5153
invariant(false, ERROR_MESSAGES.FAILED_TO_CONNECT);
5254
}
5355
}
54-
}, [brokerUrl, options, client]);
56+
}, [brokerUrl, options, client, status]);
5557

5658
useEffect(() => {
5759
init();

src/WorkflowManagerConfig.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ class WorkflowManagerConfig implements WorkflowManagerConfigProps {
114114
client?.on('message', this._onMessageArrived(topic));
115115
}
116116

117+
/**
118+
* @description Unsubscribe to a topic or topics.
119+
* @param {(string | string[])} topic
120+
* @param {IClientUnsubscribeOptions} options
121+
*/
117122
public unsubscribe(
118123
topic: string | string[],
119124
options: IClientUnsubscribeOptions = {} as IClientUnsubscribeOptions,

src/__tests__/WorkflowManager.test.tsx

Lines changed: 0 additions & 17 deletions
This file was deleted.

src/hooks/useMqtt.hook.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { ERROR_MESSAGES } from '../utils';
88
export const useMqtt = (): IMqttContext => {
99
const context = useContext(MqttContext);
1010

11-
invariant(context, ERROR_MESSAGES.NO_WRAPPER);
11+
invariant(!!context, ERROR_MESSAGES.NO_WRAPPER);
1212

1313
return context as IMqttContext;
1414
};

0 commit comments

Comments
 (0)