@internetarchive/ia-book-actions 0.0.7-7 → 0.0.8-1
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/demo/index.html +8 -1
- package/package.json +2 -2
- package/src/components/collapsible-action-group.js +0 -50
- package/src/core/services/actions-handler/actions-handler.js +2 -41
- package/src/core/services/loan-token-poller.js +87 -0
- package/src/ia-book-actions.js +69 -9
- package/test/core/services/loan-token-poller.test.js +40 -0
package/demo/index.html
CHANGED
|
@@ -104,14 +104,21 @@
|
|
|
104
104
|
const modalConfig = new ModalConfig();
|
|
105
105
|
modalConfig.headerColor = '#d9534f';
|
|
106
106
|
|
|
107
|
+
let lendingBarPostInit = function lendingBarPostInit() {
|
|
108
|
+
setTimeout(function() {
|
|
109
|
+
console.log('executed', 'br.init()');
|
|
110
|
+
}, 100);
|
|
111
|
+
}
|
|
112
|
+
|
|
107
113
|
// set defaultLendingStatus for unavailable (without borrowables) book
|
|
108
114
|
iaBookActions.userid = userid;
|
|
109
115
|
iaBookActions.identifier = identifier;
|
|
110
116
|
iaBookActions.bookTitle = 'Contemporary Black biography. Volume 39 : profiles from the interContemporary Black biography. Volume 39';
|
|
111
117
|
iaBookActions.lendingStatus = canBrowseAndBorrow;
|
|
112
118
|
iaBookActions.bwbPurchaseUrl = '';
|
|
113
|
-
iaBookActions.barType = '';
|
|
114
119
|
iaBookActions.modalConfig = modalConfig;
|
|
120
|
+
iaBookActions.lendingBarPostInit = lendingBarPostInit;
|
|
121
|
+
iaBookActions.tokenDelay = 2000; // 2 seconds
|
|
115
122
|
|
|
116
123
|
let lendingStatus1 = iaBookActions.lendingStatus;
|
|
117
124
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@internetarchive/ia-book-actions",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8-1",
|
|
4
4
|
"description": "Bookreader actions for borrowable book",
|
|
5
5
|
"author": "Internet Archive",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"@internetarchive/icon-bookmark": "^1.1.3",
|
|
23
23
|
"@internetarchive/icon-close": "^1.1.3",
|
|
24
24
|
"@internetarchive/icon-info": "^1.2.6",
|
|
25
|
-
"@internetarchive/local-cache": "^0.
|
|
25
|
+
"@internetarchive/local-cache": "^0.2.0",
|
|
26
26
|
"@internetarchive/modal-manager": "^0.1.0",
|
|
27
27
|
"@internetarchive/shared-resize-observer": "^0.0.1",
|
|
28
28
|
"lit-element": "^2.4.0",
|
|
@@ -27,7 +27,6 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
27
27
|
hasAdminAccess: { type: Boolean },
|
|
28
28
|
dropdownArrow: { type: String },
|
|
29
29
|
disabled: { type: Boolean },
|
|
30
|
-
borrowType: { type: String },
|
|
31
30
|
};
|
|
32
31
|
}
|
|
33
32
|
|
|
@@ -46,15 +45,6 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
46
45
|
this.title = '';
|
|
47
46
|
this.loaderIcon = 'https://archive.org/upload/images/tree/loading.gif';
|
|
48
47
|
this.disabled = false;
|
|
49
|
-
this.borrowType = ''; // (browsed|borrowed)
|
|
50
|
-
this.consecutiveLoanCounts = 1; // consecutive loan count
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
firstUpdated() {
|
|
54
|
-
// this is execute to fetch loan token
|
|
55
|
-
if (this.borrowType) {
|
|
56
|
-
this.emitEnableBookAccess();
|
|
57
|
-
}
|
|
58
48
|
}
|
|
59
49
|
|
|
60
50
|
updated(changed) {
|
|
@@ -63,46 +53,6 @@ export class CollapsibleActionGroup extends ActionsHandler {
|
|
|
63
53
|
}
|
|
64
54
|
}
|
|
65
55
|
|
|
66
|
-
/**
|
|
67
|
-
* Dispatches event when patron is borrowing book.
|
|
68
|
-
* Notes borrow type, and consecutive borrow counts
|
|
69
|
-
*
|
|
70
|
-
* @fires CollapsibleActionGroup#enableBookAccess
|
|
71
|
-
*/
|
|
72
|
-
async emitEnableBookAccess() {
|
|
73
|
-
// send consecutiveLoanCounts for browsed books only.
|
|
74
|
-
if (this.borrowType === 'browsed') {
|
|
75
|
-
try {
|
|
76
|
-
const existingCount = await this.localCache.get(
|
|
77
|
-
'consecutive-loan-count'
|
|
78
|
-
);
|
|
79
|
-
if (existingCount !== undefined) {
|
|
80
|
-
this.consecutiveLoanCounts = existingCount.value ?? 1;
|
|
81
|
-
}
|
|
82
|
-
} catch (error) {
|
|
83
|
-
console.log(error);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// event category and action for browsing book access
|
|
88
|
-
const eventCategory = `${this.borrowType}BookAccess`;
|
|
89
|
-
const eventAction = `${
|
|
90
|
-
this.borrowType === 'browsed' ? 'BrowseCounts-' : 'Counts-'
|
|
91
|
-
}${this.consecutiveLoanCounts}`;
|
|
92
|
-
|
|
93
|
-
this.dispatchEvent(
|
|
94
|
-
new CustomEvent('enableBookAccess', {
|
|
95
|
-
detail: {
|
|
96
|
-
event: {
|
|
97
|
-
category: eventCategory, // browsedBookAccess | borrowedBookAccess
|
|
98
|
-
action: eventAction, // (BrowseCounts-N|Counts-N)
|
|
99
|
-
},
|
|
100
|
-
borrowType: this.borrowType,
|
|
101
|
-
},
|
|
102
|
-
})
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
56
|
/**
|
|
107
57
|
* merge primaryActions and secondaryActions into dropdown
|
|
108
58
|
*/
|
|
@@ -16,18 +16,11 @@ export default class ActionsHandler extends LitElement {
|
|
|
16
16
|
constructor(identifier) {
|
|
17
17
|
super();
|
|
18
18
|
this.identifier = identifier;
|
|
19
|
-
this.ajaxTimeout =
|
|
20
|
-
this.loanTokenPollingDelay =
|
|
21
|
-
window.location.pathname === '/demo/' ? 2000 : 120000; // 120000 ms = 2 min
|
|
22
|
-
this.loanTokenInterval = undefined;
|
|
19
|
+
this.ajaxTimeout = 6000;
|
|
23
20
|
this.localCache = new LocalCache();
|
|
24
21
|
this.bindEvents();
|
|
25
22
|
}
|
|
26
23
|
|
|
27
|
-
disconnectedCallback() {
|
|
28
|
-
this.loanTokenInterval = undefined;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
24
|
sendEvent(eventCategory, eventAction) {
|
|
32
25
|
// eslint-disable-next-line no-console
|
|
33
26
|
console?.log('Book action: ', { eventCategory, eventAction });
|
|
@@ -102,26 +95,6 @@ export default class ActionsHandler extends LitElement {
|
|
|
102
95
|
const { category, action } = detail.event;
|
|
103
96
|
this.sendEvent(category, action);
|
|
104
97
|
});
|
|
105
|
-
|
|
106
|
-
this.addEventListener('enableBookAccess', ({ detail }) => {
|
|
107
|
-
const borrowType = detail?.borrowType;
|
|
108
|
-
|
|
109
|
-
// fetch loan token for browsed/borrowed book and set an interval
|
|
110
|
-
if (borrowType) {
|
|
111
|
-
// Do an initial token, then set an interval
|
|
112
|
-
this.handleLoanTokenPoller();
|
|
113
|
-
|
|
114
|
-
this.loanTokenInterval = setInterval(() => {
|
|
115
|
-
this.handleLoanTokenPoller();
|
|
116
|
-
}, this.loanTokenPollingDelay);
|
|
117
|
-
|
|
118
|
-
const { category, action } = detail?.event;
|
|
119
|
-
this.sendEvent(category, action);
|
|
120
|
-
} else {
|
|
121
|
-
// if book is not browsed, just clear token polling interval
|
|
122
|
-
clearInterval(this.loanTokenInterval);
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
98
|
}
|
|
126
99
|
|
|
127
100
|
handleBrowseIt() {
|
|
@@ -205,18 +178,6 @@ export default class ActionsHandler extends LitElement {
|
|
|
205
178
|
});
|
|
206
179
|
}
|
|
207
180
|
|
|
208
|
-
handleLoanTokenPoller() {
|
|
209
|
-
const action = 'create_token';
|
|
210
|
-
ActionsHandlerService({
|
|
211
|
-
identifier: this.identifier,
|
|
212
|
-
action,
|
|
213
|
-
error: data => {
|
|
214
|
-
this.dispatchActionError(action, data);
|
|
215
|
-
clearInterval(this.loanTokenInterval); // stop token fetch api
|
|
216
|
-
},
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
|
|
220
181
|
/**
|
|
221
182
|
* Dispatches event when an error occured on action
|
|
222
183
|
* Notes:- toggle <collapsible-action-group> visibility (enable/disable).
|
|
@@ -280,7 +241,7 @@ export default class ActionsHandler extends LitElement {
|
|
|
280
241
|
async setConsecutiveLoanCounts(action = '') {
|
|
281
242
|
try {
|
|
282
243
|
let newCount = 1;
|
|
283
|
-
const storageKey = `
|
|
244
|
+
const storageKey = `loan-count-${this.identifier}`;
|
|
284
245
|
const existingCount = await this.localCache.get(storageKey);
|
|
285
246
|
|
|
286
247
|
// increase browse-count by 1 when you consecutive reading a book.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { LocalCache } from '@internetarchive/local-cache';
|
|
2
|
+
import ActionsHandlerService from './actions-handler/actions-handler-service.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* This class is used to create loan token for borrowed books
|
|
6
|
+
*
|
|
7
|
+
* ActionsHandlerService is a function being used to execute
|
|
8
|
+
*/
|
|
9
|
+
export class LoanTokenPoller {
|
|
10
|
+
constructor(id, borrowType, successCallback, errorCallback, pollerDelay) {
|
|
11
|
+
this.identifier = id;
|
|
12
|
+
this.borrowType = borrowType;
|
|
13
|
+
this.successCallback = successCallback; // callback function to be called after loan token is created
|
|
14
|
+
this.errorCallback = errorCallback; // callback function to be called after loan token is created
|
|
15
|
+
this.pollerDelay = pollerDelay; // value in ms (1000 ms = 1 sec)
|
|
16
|
+
|
|
17
|
+
this.loanTokenInterval = undefined;
|
|
18
|
+
this.localCache = new LocalCache();
|
|
19
|
+
this.enableBookAccess();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
disconnectedInterval() {
|
|
23
|
+
clearInterval(this.loanTokenInterval);
|
|
24
|
+
this.loanTokenInterval = undefined;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async enableBookAccess() {
|
|
28
|
+
let consecutiveLoanCounts = 1;
|
|
29
|
+
|
|
30
|
+
if (this.borrowType) {
|
|
31
|
+
// send consecutiveLoanCounts for browsed books only.
|
|
32
|
+
if (this.borrowType === 'browsed') {
|
|
33
|
+
try {
|
|
34
|
+
const existingCount = await this.localCache.get(
|
|
35
|
+
`loan-count-${this.identifier}`
|
|
36
|
+
);
|
|
37
|
+
consecutiveLoanCounts = existingCount ?? 1;
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.log(error);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Do an initial token, then set an interval
|
|
44
|
+
this.handleLoanTokenPoller(true);
|
|
45
|
+
|
|
46
|
+
this.loanTokenInterval = setInterval(() => {
|
|
47
|
+
this.handleLoanTokenPoller();
|
|
48
|
+
}, this.pollerDelay);
|
|
49
|
+
|
|
50
|
+
// event category and action for browsing book access
|
|
51
|
+
const category = `${this.borrowType}BookAccess`;
|
|
52
|
+
const action = `${
|
|
53
|
+
this.borrowType === 'browsed' ? 'BrowseCounts-' : 'Counts-'
|
|
54
|
+
}${consecutiveLoanCounts}`;
|
|
55
|
+
|
|
56
|
+
this.sendEvent(category, action);
|
|
57
|
+
} else {
|
|
58
|
+
// if book is not browsed, just clear token polling interval
|
|
59
|
+
this.disconnectedInterval(); // stop token fetch api
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
sendEvent(eventCategory, eventAction) {
|
|
64
|
+
// eslint-disable-next-line no-console
|
|
65
|
+
console?.log('Book action: ', { eventCategory, eventAction });
|
|
66
|
+
window?.archive_analytics?.send_event_no_sampling(
|
|
67
|
+
eventCategory,
|
|
68
|
+
eventAction,
|
|
69
|
+
`identifier=${this.identifier}`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async handleLoanTokenPoller(isInitial = false) {
|
|
74
|
+
const action = 'create_token';
|
|
75
|
+
ActionsHandlerService({
|
|
76
|
+
identifier: this.identifier,
|
|
77
|
+
action,
|
|
78
|
+
error: data => {
|
|
79
|
+
this.disconnectedInterval(); // stop token fetch api
|
|
80
|
+
this.errorCallback({ detail: { action, data } });
|
|
81
|
+
},
|
|
82
|
+
success: () => {
|
|
83
|
+
if (isInitial) this.successCallback();
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
package/src/ia-book-actions.js
CHANGED
|
@@ -11,6 +11,7 @@ import './components/info-icon.js';
|
|
|
11
11
|
|
|
12
12
|
import GetLendingActions from './core/services/get-lending-actions.js';
|
|
13
13
|
import { mobileContainerWidth } from './core/config/constants.js';
|
|
14
|
+
import { LoanTokenPoller } from './core/services/loan-token-poller.js';
|
|
14
15
|
|
|
15
16
|
export default class IABookActions extends LitElement {
|
|
16
17
|
static get properties() {
|
|
@@ -21,10 +22,15 @@ export default class IABookActions extends LitElement {
|
|
|
21
22
|
lendingStatus: { type: Object },
|
|
22
23
|
width: { type: Number },
|
|
23
24
|
bwbPurchaseUrl: { type: String },
|
|
25
|
+
lendingBarPostInit: {
|
|
26
|
+
type: Function,
|
|
27
|
+
attribute: false,
|
|
28
|
+
},
|
|
24
29
|
barType: { type: String },
|
|
25
30
|
sharedObserver: { attribute: false },
|
|
26
31
|
disableActionGroup: { type: Boolean },
|
|
27
32
|
modal: { Object },
|
|
33
|
+
tokenDelay: { type: Number },
|
|
28
34
|
};
|
|
29
35
|
}
|
|
30
36
|
|
|
@@ -36,10 +42,12 @@ export default class IABookActions extends LitElement {
|
|
|
36
42
|
this.lendingStatus = {};
|
|
37
43
|
this.width = 0;
|
|
38
44
|
this.bwbPurchaseUrl = '';
|
|
45
|
+
this.lendingBarPostInit = () => {};
|
|
39
46
|
this.barType = 'action'; // 'title'|'action'
|
|
40
47
|
this.sharedObserver = undefined;
|
|
41
48
|
this.disableActionGroup = false;
|
|
42
49
|
this.modal = undefined;
|
|
50
|
+
this.tokenDelay = 120000; // 2 minutes
|
|
43
51
|
|
|
44
52
|
// private props
|
|
45
53
|
this.primaryActions = [];
|
|
@@ -47,6 +55,8 @@ export default class IABookActions extends LitElement {
|
|
|
47
55
|
this.primaryColor = 'primary';
|
|
48
56
|
this.secondaryActions = [];
|
|
49
57
|
this.lendingOptions = {};
|
|
58
|
+
this.borrowType = ''; // (browsed|borrowed)
|
|
59
|
+
this.consecutiveLoanCounts = 1; // consecutive loan count
|
|
50
60
|
}
|
|
51
61
|
|
|
52
62
|
disconnectedCallback() {
|
|
@@ -58,8 +68,6 @@ export default class IABookActions extends LitElement {
|
|
|
58
68
|
this.sharedObserver = new SharedResizeObserver();
|
|
59
69
|
this.setupResizeObserver();
|
|
60
70
|
}
|
|
61
|
-
|
|
62
|
-
this.setupLendingToolbarActions();
|
|
63
71
|
}
|
|
64
72
|
|
|
65
73
|
updated(changed) {
|
|
@@ -153,14 +161,26 @@ export default class IABookActions extends LitElement {
|
|
|
153
161
|
// when browse is completed, we shows browse-again button
|
|
154
162
|
this.startBrowseTimer();
|
|
155
163
|
}
|
|
164
|
+
|
|
165
|
+
// early return if not borrowed or no action-bar
|
|
166
|
+
if (!this.borrowType || this.barType === 'title') {
|
|
167
|
+
this.lendingBarPostInit();
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
this.startLoanTokenPoller();
|
|
156
172
|
}
|
|
157
173
|
|
|
158
174
|
render() {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
${this.
|
|
162
|
-
</section
|
|
163
|
-
|
|
175
|
+
if (this.barType === 'title') {
|
|
176
|
+
return html`<section class="lending-wrapper">
|
|
177
|
+
${this.bookTitleBar}
|
|
178
|
+
</section>`;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return html`<section class="lending-wrapper">
|
|
182
|
+
${this.bookActionBar}
|
|
183
|
+
</section>`;
|
|
164
184
|
}
|
|
165
185
|
|
|
166
186
|
get bookTitleBar() {
|
|
@@ -190,6 +210,40 @@ export default class IABookActions extends LitElement {
|
|
|
190
210
|
`;
|
|
191
211
|
}
|
|
192
212
|
|
|
213
|
+
/**
|
|
214
|
+
* enable access of borrowed/browsed books
|
|
215
|
+
*/
|
|
216
|
+
startLoanTokenPoller() {
|
|
217
|
+
if (this.tokenPoller) {
|
|
218
|
+
this.tokenPoller.disconnectedInterval();
|
|
219
|
+
}
|
|
220
|
+
const successCallback = () => {
|
|
221
|
+
this.lendingBarPostInit();
|
|
222
|
+
};
|
|
223
|
+
const errorCallback = eventObj => {
|
|
224
|
+
this.handleLendingActionError(eventObj);
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* LoanTokenPoller is a class that polls the loan token
|
|
229
|
+
* it takes 5 params
|
|
230
|
+
* 1. this.identifier
|
|
231
|
+
* 2. this.borrowType
|
|
232
|
+
* 3. successCallback - it used to
|
|
233
|
+
* - disptach lendingFlow::PostInit event
|
|
234
|
+
* - initialize bookreader using br.init()
|
|
235
|
+
* 4. errorCallback
|
|
236
|
+
* 5. tokenPollerDelay
|
|
237
|
+
*/
|
|
238
|
+
this.tokenPoller = new LoanTokenPoller(
|
|
239
|
+
this.identifier,
|
|
240
|
+
this.borrowType,
|
|
241
|
+
successCallback,
|
|
242
|
+
errorCallback,
|
|
243
|
+
this.tokenDelay // 1000 ms = 1 sec
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
|
|
193
247
|
/*
|
|
194
248
|
* custom event handler to toggle action group visibility
|
|
195
249
|
*
|
|
@@ -257,12 +311,18 @@ export default class IABookActions extends LitElement {
|
|
|
257
311
|
});
|
|
258
312
|
|
|
259
313
|
if (action === 'create_token') {
|
|
314
|
+
const refreshButton = html`<button
|
|
315
|
+
style="background:none;font-size:inherit;border:0;padding:0;color:#0000ee;cursor:pointer;text-decoration:underline"
|
|
316
|
+
@click=${() => window.location.reload(true)}
|
|
317
|
+
>
|
|
318
|
+
refresh
|
|
319
|
+
</button>`;
|
|
320
|
+
|
|
260
321
|
modalConfig.closeOnBackdropClick = false;
|
|
261
322
|
modalConfig.showCloseButton = false;
|
|
262
323
|
modalConfig.message = html` Uh oh, something went wrong trying to access
|
|
263
324
|
this book.<br />
|
|
264
|
-
Please
|
|
265
|
-
try again or send us an email to
|
|
325
|
+
Please ${refreshButton} to try again or send us an email to
|
|
266
326
|
<a
|
|
267
327
|
href="mailto:info@archive.org?subject=Help: cannot access my borrowed book: ${this
|
|
268
328
|
.identifier}"
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { expect } from '@open-wc/testing';
|
|
2
|
+
import Sinon from 'sinon';
|
|
3
|
+
|
|
4
|
+
import { LocalCache } from '@internetarchive/local-cache';
|
|
5
|
+
import { LoanTokenPoller } from '../../../src/core/services/loan-token-poller.js';
|
|
6
|
+
|
|
7
|
+
describe('Get Loan Token', () => {
|
|
8
|
+
it('get loan token for browsed books', async () => {
|
|
9
|
+
const localCacheStub = new LocalCache();
|
|
10
|
+
const localCacheGetSpy = Sinon.spy(localCacheStub, 'get');
|
|
11
|
+
|
|
12
|
+
const tokenPoller = new LoanTokenPoller(
|
|
13
|
+
'identifier1',
|
|
14
|
+
'browsed',
|
|
15
|
+
() => {
|
|
16
|
+
console.log('success callback is executed!');
|
|
17
|
+
},
|
|
18
|
+
() => {
|
|
19
|
+
console.log('error callback is executed!');
|
|
20
|
+
},
|
|
21
|
+
2000 // 2 minutes'
|
|
22
|
+
);
|
|
23
|
+
const successCallbackSpy = Sinon.stub(tokenPoller, 'successCallback');
|
|
24
|
+
successCallbackSpy();
|
|
25
|
+
expect(successCallbackSpy.callCount).to.equal(1);
|
|
26
|
+
|
|
27
|
+
localCacheGetSpy();
|
|
28
|
+
expect(localCacheGetSpy.callCount).to.equal(1);
|
|
29
|
+
|
|
30
|
+
expect(tokenPoller.localCache.namespace).to.equal('LocalCache');
|
|
31
|
+
expect(tokenPoller.localCache.get).to.be.a('function');
|
|
32
|
+
|
|
33
|
+
tokenPoller.disconnectedInterval(); // clear token poller interval
|
|
34
|
+
expect(tokenPoller.loanTokenInterval).to.equal(undefined);
|
|
35
|
+
|
|
36
|
+
tokenPoller.handleLoanTokenPoller(true);
|
|
37
|
+
expect(tokenPoller.errorCallback).to.be.a('function');
|
|
38
|
+
expect(tokenPoller.successCallback).have;
|
|
39
|
+
});
|
|
40
|
+
});
|