1
+ import { CWaterPumpAPIImpl } from './CWaterPumpAPIImpl.js' ;
2
+
3
+ describe ( 'CWaterPumpAPIImpl' , ( ) => {
4
+ const DUMMY_STATUS = {
5
+ pump : {
6
+ "running" : true ,
7
+ "time left" : 1000 ,
8
+ "water threshold" : 100 ,
9
+ } ,
10
+ time : 1000 ,
11
+ } ;
12
+ // common test cases
13
+ async function shouldThrowErrorFromResponse ( apiCall ) {
14
+ const mockClient = { get : jest . fn ( ) } ;
15
+ const errorMessage = 'Error ' + Math . random ( ) ;
16
+ mockClient . get . mockResolvedValue ( { data : { error : errorMessage } } ) ;
17
+
18
+ const api = new CWaterPumpAPIImpl ( { client : mockClient } ) ;
19
+ await expect ( apiCall ( api ) ) . rejects . toThrow ( errorMessage ) ;
20
+ }
21
+
22
+ async function shouldBeCalledWith ( apiCall , url , params = null ) {
23
+ const mockClient = { get : jest . fn ( ) } ;
24
+ mockClient . get . mockResolvedValue ( { data : DUMMY_STATUS } ) ;
25
+
26
+ const api = new CWaterPumpAPIImpl ( { client : mockClient } ) ;
27
+ await apiCall ( api ) ;
28
+
29
+ expect ( mockClient . get ) . toHaveBeenCalledWith ( url , params ) ;
30
+ }
31
+
32
+ async function shouldRethrowError ( apiCall ) {
33
+ const mockClient = { get : jest . fn ( ) } ;
34
+ mockClient . get . mockRejectedValue ( new Error ( 'Network Error' ) ) ;
35
+
36
+ const api = new CWaterPumpAPIImpl ( { client : mockClient } ) ;
37
+ await expect ( apiCall ( api ) ) . rejects . toThrow ( 'Network Error' ) ;
38
+ }
39
+
40
+ async function shouldPreprocessResponse ( apiCall ) {
41
+ const mockClient = { get : jest . fn ( ) } ;
42
+ mockClient . get . mockResolvedValue ( { data : DUMMY_STATUS } ) ;
43
+
44
+ const api = new CWaterPumpAPIImpl ( { client : mockClient } ) ;
45
+ const response = await apiCall ( api ) ;
46
+
47
+ expect ( response . waterThreshold ) . toBe ( DUMMY_STATUS [ "water threshold" ] ) ;
48
+ expect ( response . pump . timeLeft ) . toBe ( DUMMY_STATUS . pump [ "time left" ] ) ;
49
+ expect ( response ) . toHaveProperty ( 'updated' ) ;
50
+ }
51
+ // end of common test cases
52
+ // tests per method
53
+ describe ( 'start' , ( ) => {
54
+ it ( 'common test cases' , async ( ) => {
55
+ const T = Math . random ( ) * 1000 ;
56
+ const callback = async ( api ) => await api . start ( T ) ;
57
+ await shouldThrowErrorFromResponse ( callback ) ;
58
+ await shouldRethrowError ( callback ) ;
59
+ await shouldPreprocessResponse ( callback ) ;
60
+ await shouldBeCalledWith ( callback , '/pour_tea' , { milliseconds : T } ) ;
61
+ } ) ;
62
+ } ) ;
63
+
64
+ describe ( 'stop' , ( ) => {
65
+ it ( 'common test cases' , async ( ) => {
66
+ const callback = async ( api ) => await api . stop ( ) ;
67
+ await shouldThrowErrorFromResponse ( callback ) ;
68
+ await shouldRethrowError ( callback ) ;
69
+ await shouldPreprocessResponse ( callback ) ;
70
+ await shouldBeCalledWith ( callback , '/stop' , { } ) ;
71
+ } ) ;
72
+ } ) ;
73
+
74
+ describe ( 'status' , ( ) => {
75
+ it ( 'common test cases' , async ( ) => {
76
+ const callback = async ( api ) => await api . status ( ) ;
77
+ await shouldThrowErrorFromResponse ( callback ) ;
78
+ await shouldRethrowError ( callback ) ;
79
+ await shouldPreprocessResponse ( callback ) ;
80
+ await shouldBeCalledWith ( callback , '/status' , { } ) ;
81
+ } ) ;
82
+ } ) ;
83
+ // tests for helper function preprocessResponse
84
+ describe ( 'preprocessResponse' , ( ) => {
85
+ it ( 'should return null if response is null' , ( ) => {
86
+ const api = new CWaterPumpAPIImpl ( { client : { } } ) ;
87
+ expect ( api . preprocessResponse ( { response : null , requestTime : 0 } ) ) . toBeNull ( ) ;
88
+ } ) ;
89
+
90
+ it ( 'should throw error if response has error' , ( ) => {
91
+ const api = new CWaterPumpAPIImpl ( { client : { } } ) ;
92
+ const errorMessage = 'Error ' + Math . random ( ) ;
93
+ expect ( ( ) => api . preprocessResponse ( {
94
+ response : { error : errorMessage } ,
95
+ requestTime : 0 ,
96
+ } ) ) . toThrow ( errorMessage ) ;
97
+ } ) ;
98
+
99
+ it ( 'should preprocess response' , ( ) => {
100
+ const api = new CWaterPumpAPIImpl ( { client : { } } ) ;
101
+ const response = api . preprocessResponse ( { response : DUMMY_STATUS , requestTime : 0 } ) ;
102
+ expect ( response . waterThreshold ) . toBe ( DUMMY_STATUS [ "water threshold" ] ) ;
103
+ expect ( response . pump . timeLeft ) . toBe ( DUMMY_STATUS . pump [ "time left" ] ) ;
104
+ } ) ;
105
+
106
+ it ( 'should add field "updated" with current time' , ( ) => {
107
+ const T = Math . random ( ) * 1000 ;
108
+ const api = new CWaterPumpAPIImpl ( { client : { } , currentTime : ( ) => T } ) ;
109
+ const response = api . preprocessResponse ( { response : DUMMY_STATUS , requestTime : 0 } ) ;
110
+ expect ( response . updated ) . toBe ( T ) ;
111
+ } ) ;
112
+
113
+ ///////////
114
+ // Scenario:
115
+ // 00:00.000 - client sends request
116
+ // 00:00.100 - server receives request and set 'time' to 00:00.100, timeLeft = 1234ms
117
+ // 00:00.200 - server sends response
118
+ // 00:00.300 - client receives response, but 'time' is 00:00.100 and timeLeft = 1234ms
119
+ // total time: 300ms
120
+ // on average, time to one-way trip is 150ms
121
+ // so, we adjust time by 150ms i.e. time = 00:00.250, timeLeft = 1084ms
122
+ // estimatedEndTime = 00:00.300 + 1084ms = 00:01.384
123
+ it ( 'should adjust time' , ( ) => {
124
+ const responseObj = JSON . parse ( JSON . stringify ( DUMMY_STATUS ) ) ;
125
+ responseObj . time = 100 ;
126
+ responseObj . pump [ "time left" ] = 1234 ;
127
+
128
+ const api = new CWaterPumpAPIImpl ( { client : { } , currentTime : ( ) => 300 } ) ;
129
+ const response = api . preprocessResponse ( { response : responseObj , requestTime : 300 } ) ;
130
+ expect ( response . time ) . toBe ( 250 ) ;
131
+ expect ( response . pump . timeLeft ) . toBe ( 1084 ) ;
132
+ expect ( response . pump . estimatedEndTime ) . toBe ( 1384 ) ;
133
+ } ) ;
134
+ } ) ;
135
+ } ) ;
0 commit comments