@b-jones-rfd/qualtrics-api-tasks 0.0.5 → 0.1.0
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/CHANGELOG.md +6 -0
- package/README.md +96 -7
- package/dist/index.d.mts +71 -3
- package/dist/index.d.ts +71 -3
- package/dist/index.js +167 -12
- package/dist/index.mjs +163 -12
- package/package.json +1 -1
- package/tests/utils.test.ts +109 -3
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -139,23 +139,112 @@ export type Action<TConfig, TResponse> = (
|
|
|
139
139
|
|
|
140
140
|
If using the actions directly call the factory method with a ConnectionOptions object to return an action that can be used to execute a Qualtrics action.
|
|
141
141
|
|
|
142
|
-
####
|
|
142
|
+
#### exportResponses(options)
|
|
143
|
+
|
|
144
|
+
Implements [Survey Response File Export](https://api.qualtrics.com/u9e5lh4172v0v-survey-response-export-guide) multistep process.
|
|
145
|
+
|
|
146
|
+
`options`
|
|
147
|
+
|
|
148
|
+
| Property | Type | Description | Required | Default |
|
|
149
|
+
| ------------------------------- | -------- | ------------------------------------------- | -------- | ------- |
|
|
150
|
+
| surveyId | string | Quatrics Survey ID | Y | |
|
|
151
|
+
| startDate | Date | Export start date and time | Y | |
|
|
152
|
+
| endDate | Date | Export end date and time | Y | |
|
|
153
|
+
| format | Enum | File format | N | 'csv' |
|
|
154
|
+
| breakoutSets | boolean | Split multi-value fields into columns | N | true |
|
|
155
|
+
| compress | boolean | Compress final export | N | true |
|
|
156
|
+
| exportResponsesInProgress | boolean | Only export not complete | N | false |
|
|
157
|
+
| filterId | string | Return responses matching id | N | |
|
|
158
|
+
| formatDecimalAsComma | boolean | Use comma as decimal separator | N | false |
|
|
159
|
+
| includeDisplayOrder | boolean | Include display order in export | N | false |
|
|
160
|
+
| limit | number | Max responses to export | N | |
|
|
161
|
+
| multiselectSeenUnansweredRecode | number | Recode seen, but unanswered for multiselect | N | |
|
|
162
|
+
| newlineReplacement | string | Replace newline character with this | N | |
|
|
163
|
+
| seenUnansweredRecode | number | Recode seen, but unanswered with this | N | |
|
|
164
|
+
| timeZone | string | Timezone used to determine response date | N | 'UTC" |
|
|
165
|
+
| useLabels | boolean | Export text of answer choice | N | false |
|
|
166
|
+
| embeddedDataIds | string[] | Only export these embedded data fields | N | |
|
|
167
|
+
| questionIds | string[] | Only export these question IDs | N | |
|
|
168
|
+
| surveyMetadataIds | string[] | Only export these metadata fields | N | |
|
|
169
|
+
| continuationToken | string | Previous export continuation token | N | |
|
|
170
|
+
| allowContinuation | boolean | Request continuation token | N | false |
|
|
171
|
+
| includeLabelColumns | boolean | Export two columns, recode and labels | N | false |
|
|
172
|
+
| sortByLastModifiedDate | boolean | Sort responses by modified date | N | false |
|
|
173
|
+
| bearerToken | string | Valid Bearer Token | N | |
|
|
174
|
+
|
|
175
|
+
#### getBearerToken(options)
|
|
143
176
|
|
|
144
177
|
Implements [OAuth Authentication (Client Credentials)](https://api.qualtrics.com/9398592961ced-o-auth-authentication-client-credentials)
|
|
145
178
|
|
|
146
179
|
`options`
|
|
147
180
|
|
|
148
|
-
| Property | Type | Description
|
|
149
|
-
| ------------ | ------ |
|
|
150
|
-
| clientId | string | Quatrics Client ID
|
|
151
|
-
| clientSecret | string | Qualtrics Client Password
|
|
181
|
+
| Property | Type | Description | Required |
|
|
182
|
+
| ------------ | ------ | --------------------------------- | -------- |
|
|
183
|
+
| clientId | string | Quatrics Client ID | Y |
|
|
184
|
+
| clientSecret | string | Qualtrics Client Password | Y |
|
|
185
|
+
| scope | string | Qualtrics Client requested scopes | Y |
|
|
186
|
+
|
|
187
|
+
#### getResponseExportFile(options)
|
|
152
188
|
|
|
153
|
-
|
|
189
|
+
Implements [Get Response Export File](https://api.qualtrics.com/41296b6f2e828-get-response-export-file)
|
|
154
190
|
|
|
155
191
|
`options`
|
|
156
192
|
|
|
157
193
|
| Property | Type | Description | Required |
|
|
158
194
|
| ----------- | ------ | ------------------ | -------- |
|
|
195
|
+
| surveyId | string | Quatrics Survey ID | Y |
|
|
196
|
+
| fileId | string | File ID | Y |
|
|
197
|
+
| bearerToken | string | Valid Bearer Token | N |
|
|
198
|
+
|
|
199
|
+
#### getResponseExportProgress(options)
|
|
200
|
+
|
|
201
|
+
Implements [Get Response Export Progress](https://api.qualtrics.com/37e6a66f74ab4-get-response-export-progress)
|
|
202
|
+
|
|
203
|
+
`options`
|
|
204
|
+
|
|
205
|
+
| Property | Type | Description | Required |
|
|
206
|
+
| ---------------- | ------ | ------------------ | -------- |
|
|
207
|
+
| surveyId | string | Quatrics Survey ID | Y |
|
|
208
|
+
| exportProgressId | string | Progress ID | Y |
|
|
209
|
+
| bearerToken | string | Valid Bearer Token | N |
|
|
210
|
+
|
|
211
|
+
#### startResponseExports(options)
|
|
212
|
+
|
|
213
|
+
Implements [Start Response Exports](https://api.qualtrics.com/6b00592b9c013-start-response-export)
|
|
214
|
+
|
|
215
|
+
`options`
|
|
216
|
+
|
|
217
|
+
| Property | Type | Description | Required | Default |
|
|
218
|
+
| ------------------------------- | -------- | ------------------------------------------- | -------- | ------- |
|
|
219
|
+
| surveyId | string | Quatrics Survey ID | Y | |
|
|
220
|
+
| startDate | Date | Export start date and time | Y | |
|
|
221
|
+
| endDate | Date | Export end date and time | Y | |
|
|
222
|
+
| format | Enum | File format | N | 'csv' |
|
|
223
|
+
| breakoutSets | boolean | Split multi-value fields into columns | N | true |
|
|
224
|
+
| compress | boolean | Compress final export | N | true |
|
|
225
|
+
| exportResponsesInProgress | boolean | Only export not complete | N | false |
|
|
226
|
+
| filterId | string | Return responses matching id | N | |
|
|
227
|
+
| formatDecimalAsComma | boolean | Use comma as decimal separator | N | false |
|
|
228
|
+
| includeDisplayOrder | boolean | Include display order in export | N | false |
|
|
229
|
+
| limit | number | Max responses to export | N | |
|
|
230
|
+
| multiselectSeenUnansweredRecode | number | Recode seen, but unanswered for multiselect | N | |
|
|
231
|
+
| newlineReplacement | string | Replace newline character with this | N | |
|
|
232
|
+
| seenUnansweredRecode | number | Recode seen, but unanswered with this | N | |
|
|
233
|
+
| timeZone | string | Timezone used to determine response date | N | 'UTC" |
|
|
234
|
+
| useLabels | boolean | Export text of answer choice | N | false |
|
|
235
|
+
| embeddedDataIds | string[] | Only export these embedded data fields | N | |
|
|
236
|
+
| questionIds | string[] | Only export these question IDs | N | |
|
|
237
|
+
| surveyMetadataIds | string[] | Only export these metadata fields | N | |
|
|
238
|
+
| continuationToken | string | Previous export continuation token | N | |
|
|
239
|
+
| allowContinuation | boolean | Request continuation token | N | false |
|
|
240
|
+
| includeLabelColumns | boolean | Export two columns, recode and labels | N | false |
|
|
241
|
+
| sortByLastModifiedDate | boolean | Sort responses by modified date | N | false |
|
|
242
|
+
| bearerToken | string | Valid Bearer Token | N | |
|
|
243
|
+
|
|
244
|
+
#### testConnection(bearerToken)
|
|
245
|
+
|
|
246
|
+
| Parameter | Type | Description | Required |
|
|
247
|
+
| ----------- | ------ | ------------------ | -------- |
|
|
159
248
|
| bearerToken | string | Valid Bearer Token | N |
|
|
160
249
|
|
|
161
250
|
## Responses
|
|
@@ -196,4 +285,4 @@ We use [SemVer](http://semver.org/) for versioning. For the versions available,
|
|
|
196
285
|
|
|
197
286
|
## License
|
|
198
287
|
|
|
199
|
-
[MIT License](https://github.com/B-Jones-RFD/
|
|
288
|
+
[MIT License](https://github.com/B-Jones-RFD/qualtrics-api-tasks/blob/main/LICENSE)
|
package/dist/index.d.mts
CHANGED
|
@@ -7,6 +7,7 @@ type Failure = {
|
|
|
7
7
|
error: string;
|
|
8
8
|
};
|
|
9
9
|
type Result<T> = Success<T> | Failure;
|
|
10
|
+
type ResponseFormat = 'csv' | 'json' | 'ndjson' | 'spss' | 'tsv' | 'xml';
|
|
10
11
|
type Action<TConfig, TResponse> = (options: TConfig) => Promise<Result<TResponse>>;
|
|
11
12
|
type ConnectionOptions = {
|
|
12
13
|
datacenterId: string;
|
|
@@ -15,21 +16,88 @@ type ConnectionOptions = {
|
|
|
15
16
|
};
|
|
16
17
|
type ActionFactory<TParams, TResponse> = (options: ConnectionOptions) => Action<TParams, TResponse>;
|
|
17
18
|
type Connection = {
|
|
18
|
-
|
|
19
|
+
exportResponses: Action<ExportResponsesOptions, Buffer>;
|
|
19
20
|
getBearerToken: Action<{
|
|
20
21
|
clientId: string;
|
|
21
22
|
clientSecret: string;
|
|
23
|
+
scope: string;
|
|
22
24
|
}, string>;
|
|
25
|
+
getResponseExportProgress: Action<{
|
|
26
|
+
exportProgressId: string;
|
|
27
|
+
surveyId: string;
|
|
28
|
+
bearerToken?: string;
|
|
29
|
+
}, FileProgressResponse>;
|
|
30
|
+
startResponseExport: Action<ExportResponsesOptions, {
|
|
31
|
+
progressId: string;
|
|
32
|
+
percentComplete: number;
|
|
33
|
+
status: string;
|
|
34
|
+
continuationToken?: string;
|
|
35
|
+
}>;
|
|
36
|
+
testConnection: (bearerToken?: string) => Promise<Result<void>>;
|
|
23
37
|
};
|
|
24
38
|
type ConnectionFactory = (options: ConnectionOptions) => Connection;
|
|
39
|
+
type ExportResponsesOptions = {
|
|
40
|
+
surveyId: string;
|
|
41
|
+
startDate: Date;
|
|
42
|
+
endDate: Date;
|
|
43
|
+
format?: ResponseFormat;
|
|
44
|
+
breakoutSets?: boolean;
|
|
45
|
+
compress?: boolean;
|
|
46
|
+
exportResponsesInProgress?: boolean;
|
|
47
|
+
filterId?: string;
|
|
48
|
+
formatDecimalAsComma?: boolean;
|
|
49
|
+
includeDisplayOrder?: boolean;
|
|
50
|
+
limit?: number;
|
|
51
|
+
multiselectSeenUnansweredRecode?: number;
|
|
52
|
+
newlineReplacement?: string;
|
|
53
|
+
seenUnansweredRecode?: number;
|
|
54
|
+
timeZone?: string;
|
|
55
|
+
useLabels?: boolean;
|
|
56
|
+
embeddedDataIds?: string[];
|
|
57
|
+
questionIds?: string[];
|
|
58
|
+
surveyMetadataIds?: string[];
|
|
59
|
+
continuationToken?: string;
|
|
60
|
+
allowContinuation?: boolean;
|
|
61
|
+
includeLabelColumns?: boolean;
|
|
62
|
+
sortByLastModifiedDate?: boolean;
|
|
63
|
+
bearerToken?: string;
|
|
64
|
+
};
|
|
65
|
+
type FileProgressResponse = {
|
|
66
|
+
fileId: string;
|
|
67
|
+
percentComplete: number;
|
|
68
|
+
status: string;
|
|
69
|
+
continuationToken?: string;
|
|
70
|
+
};
|
|
25
71
|
|
|
26
72
|
declare const createConnection: ConnectionFactory;
|
|
27
73
|
|
|
74
|
+
declare const exportResponses: ActionFactory<ExportResponsesOptions, Buffer>;
|
|
75
|
+
|
|
28
76
|
declare const getBearerToken: ActionFactory<{
|
|
29
77
|
clientId: string;
|
|
30
78
|
clientSecret: string;
|
|
79
|
+
scope: string;
|
|
31
80
|
}, string>;
|
|
32
81
|
|
|
33
|
-
declare const
|
|
82
|
+
declare const getResponseExportProgress: ActionFactory<{
|
|
83
|
+
exportProgressId: string;
|
|
84
|
+
surveyId: string;
|
|
85
|
+
bearerToken?: string;
|
|
86
|
+
}, FileProgressResponse>;
|
|
87
|
+
|
|
88
|
+
declare const getResponseExportFile: ActionFactory<{
|
|
89
|
+
surveyId: string;
|
|
90
|
+
fileId: string;
|
|
91
|
+
bearerToken?: string;
|
|
92
|
+
}, Buffer>;
|
|
93
|
+
|
|
94
|
+
declare const startResponseExport: ActionFactory<ExportResponsesOptions, {
|
|
95
|
+
progressId: string;
|
|
96
|
+
percentComplete: number;
|
|
97
|
+
status: string;
|
|
98
|
+
continuationToken?: string;
|
|
99
|
+
}>;
|
|
100
|
+
|
|
101
|
+
declare const testConnection: (connectionOptions: ConnectionOptions) => (bearerToken?: string) => Promise<Result<void>>;
|
|
34
102
|
|
|
35
|
-
export { type Action, type ActionFactory, type Connection, type ConnectionFactory, type ConnectionOptions, type Failure, type Result, type Success, createConnection, getBearerToken, testConnection };
|
|
103
|
+
export { type Action, type ActionFactory, type Connection, type ConnectionFactory, type ConnectionOptions, type ExportResponsesOptions, type Failure, type FileProgressResponse, type ResponseFormat, type Result, type Success, createConnection, exportResponses, getBearerToken, getResponseExportFile, getResponseExportProgress, startResponseExport, testConnection };
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ type Failure = {
|
|
|
7
7
|
error: string;
|
|
8
8
|
};
|
|
9
9
|
type Result<T> = Success<T> | Failure;
|
|
10
|
+
type ResponseFormat = 'csv' | 'json' | 'ndjson' | 'spss' | 'tsv' | 'xml';
|
|
10
11
|
type Action<TConfig, TResponse> = (options: TConfig) => Promise<Result<TResponse>>;
|
|
11
12
|
type ConnectionOptions = {
|
|
12
13
|
datacenterId: string;
|
|
@@ -15,21 +16,88 @@ type ConnectionOptions = {
|
|
|
15
16
|
};
|
|
16
17
|
type ActionFactory<TParams, TResponse> = (options: ConnectionOptions) => Action<TParams, TResponse>;
|
|
17
18
|
type Connection = {
|
|
18
|
-
|
|
19
|
+
exportResponses: Action<ExportResponsesOptions, Buffer>;
|
|
19
20
|
getBearerToken: Action<{
|
|
20
21
|
clientId: string;
|
|
21
22
|
clientSecret: string;
|
|
23
|
+
scope: string;
|
|
22
24
|
}, string>;
|
|
25
|
+
getResponseExportProgress: Action<{
|
|
26
|
+
exportProgressId: string;
|
|
27
|
+
surveyId: string;
|
|
28
|
+
bearerToken?: string;
|
|
29
|
+
}, FileProgressResponse>;
|
|
30
|
+
startResponseExport: Action<ExportResponsesOptions, {
|
|
31
|
+
progressId: string;
|
|
32
|
+
percentComplete: number;
|
|
33
|
+
status: string;
|
|
34
|
+
continuationToken?: string;
|
|
35
|
+
}>;
|
|
36
|
+
testConnection: (bearerToken?: string) => Promise<Result<void>>;
|
|
23
37
|
};
|
|
24
38
|
type ConnectionFactory = (options: ConnectionOptions) => Connection;
|
|
39
|
+
type ExportResponsesOptions = {
|
|
40
|
+
surveyId: string;
|
|
41
|
+
startDate: Date;
|
|
42
|
+
endDate: Date;
|
|
43
|
+
format?: ResponseFormat;
|
|
44
|
+
breakoutSets?: boolean;
|
|
45
|
+
compress?: boolean;
|
|
46
|
+
exportResponsesInProgress?: boolean;
|
|
47
|
+
filterId?: string;
|
|
48
|
+
formatDecimalAsComma?: boolean;
|
|
49
|
+
includeDisplayOrder?: boolean;
|
|
50
|
+
limit?: number;
|
|
51
|
+
multiselectSeenUnansweredRecode?: number;
|
|
52
|
+
newlineReplacement?: string;
|
|
53
|
+
seenUnansweredRecode?: number;
|
|
54
|
+
timeZone?: string;
|
|
55
|
+
useLabels?: boolean;
|
|
56
|
+
embeddedDataIds?: string[];
|
|
57
|
+
questionIds?: string[];
|
|
58
|
+
surveyMetadataIds?: string[];
|
|
59
|
+
continuationToken?: string;
|
|
60
|
+
allowContinuation?: boolean;
|
|
61
|
+
includeLabelColumns?: boolean;
|
|
62
|
+
sortByLastModifiedDate?: boolean;
|
|
63
|
+
bearerToken?: string;
|
|
64
|
+
};
|
|
65
|
+
type FileProgressResponse = {
|
|
66
|
+
fileId: string;
|
|
67
|
+
percentComplete: number;
|
|
68
|
+
status: string;
|
|
69
|
+
continuationToken?: string;
|
|
70
|
+
};
|
|
25
71
|
|
|
26
72
|
declare const createConnection: ConnectionFactory;
|
|
27
73
|
|
|
74
|
+
declare const exportResponses: ActionFactory<ExportResponsesOptions, Buffer>;
|
|
75
|
+
|
|
28
76
|
declare const getBearerToken: ActionFactory<{
|
|
29
77
|
clientId: string;
|
|
30
78
|
clientSecret: string;
|
|
79
|
+
scope: string;
|
|
31
80
|
}, string>;
|
|
32
81
|
|
|
33
|
-
declare const
|
|
82
|
+
declare const getResponseExportProgress: ActionFactory<{
|
|
83
|
+
exportProgressId: string;
|
|
84
|
+
surveyId: string;
|
|
85
|
+
bearerToken?: string;
|
|
86
|
+
}, FileProgressResponse>;
|
|
87
|
+
|
|
88
|
+
declare const getResponseExportFile: ActionFactory<{
|
|
89
|
+
surveyId: string;
|
|
90
|
+
fileId: string;
|
|
91
|
+
bearerToken?: string;
|
|
92
|
+
}, Buffer>;
|
|
93
|
+
|
|
94
|
+
declare const startResponseExport: ActionFactory<ExportResponsesOptions, {
|
|
95
|
+
progressId: string;
|
|
96
|
+
percentComplete: number;
|
|
97
|
+
status: string;
|
|
98
|
+
continuationToken?: string;
|
|
99
|
+
}>;
|
|
100
|
+
|
|
101
|
+
declare const testConnection: (connectionOptions: ConnectionOptions) => (bearerToken?: string) => Promise<Result<void>>;
|
|
34
102
|
|
|
35
|
-
export { type Action, type ActionFactory, type Connection, type ConnectionFactory, type ConnectionOptions, type Failure, type Result, type Success, createConnection, getBearerToken, testConnection };
|
|
103
|
+
export { type Action, type ActionFactory, type Connection, type ConnectionFactory, type ConnectionOptions, type ExportResponsesOptions, type Failure, type FileProgressResponse, type ResponseFormat, type Result, type Success, createConnection, exportResponses, getBearerToken, getResponseExportFile, getResponseExportProgress, startResponseExport, testConnection };
|
package/dist/index.js
CHANGED
|
@@ -21,12 +21,16 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var src_exports = {};
|
|
22
22
|
__export(src_exports, {
|
|
23
23
|
createConnection: () => createConnection,
|
|
24
|
+
exportResponses: () => exportResponses,
|
|
24
25
|
getBearerToken: () => getBearerToken,
|
|
26
|
+
getResponseExportFile: () => getResponseExportFile,
|
|
27
|
+
getResponseExportProgress: () => getResponseExportProgress,
|
|
28
|
+
startResponseExport: () => startResponseExport,
|
|
25
29
|
testConnection: () => testConnection
|
|
26
30
|
});
|
|
27
31
|
module.exports = __toCommonJS(src_exports);
|
|
28
32
|
|
|
29
|
-
// src/utils.ts
|
|
33
|
+
// src/utils/index.ts
|
|
30
34
|
function success(data) {
|
|
31
35
|
return {
|
|
32
36
|
success: true,
|
|
@@ -42,12 +46,6 @@ function failure(error) {
|
|
|
42
46
|
function getErrorMessage(error) {
|
|
43
47
|
return error ? typeof error === "object" && "message" in error && typeof error.message === "string" ? error.message : error.toString() : "An error occured";
|
|
44
48
|
}
|
|
45
|
-
function safeParseBearerToken(response) {
|
|
46
|
-
return response?.access_token && typeof response.access_token === "string" ? success(response.access_token) : failure("Incorrect token format");
|
|
47
|
-
}
|
|
48
|
-
function safeParseTestResponse(response) {
|
|
49
|
-
return response?.result?.userId ? success(void 0) : failure("Incorrect test response format");
|
|
50
|
-
}
|
|
51
49
|
function getAuthHeaders(apiToken, bearerToken) {
|
|
52
50
|
if (apiToken)
|
|
53
51
|
return new Headers({
|
|
@@ -55,7 +53,7 @@ function getAuthHeaders(apiToken, bearerToken) {
|
|
|
55
53
|
});
|
|
56
54
|
if (bearerToken) {
|
|
57
55
|
return new Headers({
|
|
58
|
-
Authorization: bearerToken
|
|
56
|
+
Authorization: `Bearer ${bearerToken}`
|
|
59
57
|
});
|
|
60
58
|
}
|
|
61
59
|
throw new Error(
|
|
@@ -63,6 +61,82 @@ function getAuthHeaders(apiToken, bearerToken) {
|
|
|
63
61
|
);
|
|
64
62
|
}
|
|
65
63
|
|
|
64
|
+
// src/utils/poll.ts
|
|
65
|
+
async function poll({
|
|
66
|
+
fn,
|
|
67
|
+
validate,
|
|
68
|
+
interval,
|
|
69
|
+
maxAttempts
|
|
70
|
+
}) {
|
|
71
|
+
let attempts = 0;
|
|
72
|
+
const executePoll = async (resolve, reject) => {
|
|
73
|
+
try {
|
|
74
|
+
const result = await fn();
|
|
75
|
+
attempts++;
|
|
76
|
+
if (validate(result)) {
|
|
77
|
+
return resolve(result);
|
|
78
|
+
} else if (maxAttempts && attempts === maxAttempts) {
|
|
79
|
+
return reject(new Error("Exceeded max attempts"));
|
|
80
|
+
} else {
|
|
81
|
+
setTimeout(executePoll, interval, resolve, reject);
|
|
82
|
+
}
|
|
83
|
+
} catch (error) {
|
|
84
|
+
reject(new Error(`Poll function execution failed: ${error}`));
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
return new Promise(executePoll);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// src/methods/exportResponses.ts
|
|
91
|
+
var exportResponses = (connectionOptions) => async (responseOptions) => {
|
|
92
|
+
try {
|
|
93
|
+
const startResponseAction = startResponseExport(connectionOptions);
|
|
94
|
+
const startResponse = await startResponseAction(responseOptions);
|
|
95
|
+
if (!startResponse.success)
|
|
96
|
+
return failure(startResponse.error);
|
|
97
|
+
const exportProgressAction = getResponseExportProgress(connectionOptions);
|
|
98
|
+
const progressResponse = await poll({
|
|
99
|
+
fn: async () => await exportProgressAction({
|
|
100
|
+
exportProgressId: startResponse.data.progressId,
|
|
101
|
+
surveyId: responseOptions.surveyId,
|
|
102
|
+
bearerToken: responseOptions.bearerToken
|
|
103
|
+
}),
|
|
104
|
+
validate: (res) => res.success && res.data.percentComplete === 100,
|
|
105
|
+
interval: 1,
|
|
106
|
+
maxAttempts: 60
|
|
107
|
+
});
|
|
108
|
+
if (!progressResponse.success)
|
|
109
|
+
return failure(progressResponse.error);
|
|
110
|
+
const getFileResponseAction = getResponseExportFile(connectionOptions);
|
|
111
|
+
const fileResponse = await getFileResponseAction({
|
|
112
|
+
surveyId: responseOptions.surveyId,
|
|
113
|
+
fileId: progressResponse.data.fileId,
|
|
114
|
+
bearerToken: responseOptions.bearerToken
|
|
115
|
+
});
|
|
116
|
+
return fileResponse;
|
|
117
|
+
} catch (error) {
|
|
118
|
+
const message = getErrorMessage(error);
|
|
119
|
+
return failure(message);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// src/utils/parsers.ts
|
|
124
|
+
function safeParseBearerToken(response) {
|
|
125
|
+
return response?.access_token && typeof response.access_token === "string" ? success(response.access_token) : failure("Incorrect token format");
|
|
126
|
+
}
|
|
127
|
+
function safeParseTestResponse(response) {
|
|
128
|
+
return response?.result?.userId ? success(void 0) : failure("Incorrect test response format");
|
|
129
|
+
}
|
|
130
|
+
function safeParseStartFileExportResponse(response) {
|
|
131
|
+
return "result" in response ? "progressId" in response.result && "percentComplete" in response.result && "status" in response.result ? success(response.result) : failure("Start Export Response invalid format") : "error" in response ? failure(`${response.error.errorCode}: ${response.error.errorMessage}`) : failure(`Unable to parse Start Export Response`);
|
|
132
|
+
}
|
|
133
|
+
function safeParseFileProgressResponse(response) {
|
|
134
|
+
return "result" in response ? "fileId" in response.result && "percentComplete" in response.result && "status" in response.result ? success(response.result) : failure("File Progress Response invalid format") : "error" in response ? failure(`${response.error.errorCode}: ${response.error.errorMessage}`) : failure(`Unable to parse File Progress Response`);
|
|
135
|
+
}
|
|
136
|
+
function safeParseFileResponse(response) {
|
|
137
|
+
return Buffer.isBuffer(response) ? success(response) : failure("Incorrect file response format");
|
|
138
|
+
}
|
|
139
|
+
|
|
66
140
|
// src/qualtrics/index.ts
|
|
67
141
|
async function execute(config) {
|
|
68
142
|
const { datacenterId, route, headers, timeout, body } = config;
|
|
@@ -94,7 +168,7 @@ async function execute(config) {
|
|
|
94
168
|
}
|
|
95
169
|
|
|
96
170
|
// src/methods/getBearerToken.ts
|
|
97
|
-
var getBearerToken = (connectionOptions) => async ({ clientId, clientSecret }) => {
|
|
171
|
+
var getBearerToken = (connectionOptions) => async ({ clientId, clientSecret, scope }) => {
|
|
98
172
|
const route = `/oauth2/token`;
|
|
99
173
|
try {
|
|
100
174
|
const { datacenterId, timeout } = connectionOptions;
|
|
@@ -103,7 +177,7 @@ var getBearerToken = (connectionOptions) => async ({ clientId, clientSecret }) =
|
|
|
103
177
|
});
|
|
104
178
|
const body = new FormData();
|
|
105
179
|
body.append("grant_type", "client_credentials");
|
|
106
|
-
body.append("scope",
|
|
180
|
+
body.append("scope", scope);
|
|
107
181
|
const response = await execute({
|
|
108
182
|
datacenterId,
|
|
109
183
|
route,
|
|
@@ -119,6 +193,80 @@ var getBearerToken = (connectionOptions) => async ({ clientId, clientSecret }) =
|
|
|
119
193
|
}
|
|
120
194
|
};
|
|
121
195
|
|
|
196
|
+
// src/methods/getResponseExportProgress.ts
|
|
197
|
+
var getResponseExportProgress = (connectionOptions) => async ({ exportProgressId, surveyId, bearerToken }) => {
|
|
198
|
+
const route = `/surveys/${surveyId}/export-responses/${exportProgressId}`;
|
|
199
|
+
try {
|
|
200
|
+
const headers = getAuthHeaders(connectionOptions.apiToken, bearerToken);
|
|
201
|
+
const config = {
|
|
202
|
+
datacenterId: connectionOptions.datacenterId,
|
|
203
|
+
route,
|
|
204
|
+
headers,
|
|
205
|
+
timeout: connectionOptions.timeout
|
|
206
|
+
};
|
|
207
|
+
const response = await execute(config);
|
|
208
|
+
const result = safeParseFileProgressResponse(response);
|
|
209
|
+
return result;
|
|
210
|
+
} catch (error) {
|
|
211
|
+
const message = getErrorMessage(error);
|
|
212
|
+
return failure(message);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
// src/methods/getResponseExportFile.ts
|
|
217
|
+
var getResponseExportFile = (connectionOptions) => async ({ surveyId, fileId, bearerToken }) => {
|
|
218
|
+
const route = `/surveys/${surveyId}/export-responses/${fileId}/file`;
|
|
219
|
+
try {
|
|
220
|
+
const headers = getAuthHeaders(connectionOptions.apiToken, bearerToken);
|
|
221
|
+
const config = {
|
|
222
|
+
datacenterId: connectionOptions.datacenterId,
|
|
223
|
+
route,
|
|
224
|
+
headers,
|
|
225
|
+
timeout: connectionOptions.timeout
|
|
226
|
+
};
|
|
227
|
+
const response = await execute(config);
|
|
228
|
+
const result = safeParseFileResponse(response);
|
|
229
|
+
return result;
|
|
230
|
+
} catch (error) {
|
|
231
|
+
const message = getErrorMessage(error);
|
|
232
|
+
return failure(message);
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
// src/methods/startResponseExport.ts
|
|
237
|
+
var startResponseExport = (connectionOptions) => async ({
|
|
238
|
+
surveyId,
|
|
239
|
+
startDate,
|
|
240
|
+
endDate,
|
|
241
|
+
format = "csv",
|
|
242
|
+
bearerToken = void 0,
|
|
243
|
+
...rest
|
|
244
|
+
}) => {
|
|
245
|
+
const route = `/surveys/${surveyId}/export-responses`;
|
|
246
|
+
try {
|
|
247
|
+
const headers = getAuthHeaders(connectionOptions.apiToken, bearerToken);
|
|
248
|
+
const body = JSON.stringify({
|
|
249
|
+
startDate: startDate.toISOString(),
|
|
250
|
+
endDate: endDate.toDateString(),
|
|
251
|
+
format,
|
|
252
|
+
...rest
|
|
253
|
+
});
|
|
254
|
+
const config = {
|
|
255
|
+
datacenterId: connectionOptions.datacenterId,
|
|
256
|
+
route,
|
|
257
|
+
headers,
|
|
258
|
+
body,
|
|
259
|
+
timeout: connectionOptions.timeout
|
|
260
|
+
};
|
|
261
|
+
const response = await execute(config);
|
|
262
|
+
const result = safeParseStartFileExportResponse(response);
|
|
263
|
+
return result;
|
|
264
|
+
} catch (error) {
|
|
265
|
+
const message = getErrorMessage(error);
|
|
266
|
+
return failure(message);
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
|
|
122
270
|
// src/methods/testConnection.ts
|
|
123
271
|
var testConnection = (connectionOptions) => async (bearerToken) => {
|
|
124
272
|
const route = "/API/v3/whoami";
|
|
@@ -141,12 +289,19 @@ var testConnection = (connectionOptions) => async (bearerToken) => {
|
|
|
141
289
|
|
|
142
290
|
// src/createConnection.ts
|
|
143
291
|
var createConnection = (options) => ({
|
|
144
|
-
|
|
145
|
-
getBearerToken: getBearerToken(options)
|
|
292
|
+
exportResponses: exportResponses(options),
|
|
293
|
+
getBearerToken: getBearerToken(options),
|
|
294
|
+
getResponseExportProgress: getResponseExportProgress(options),
|
|
295
|
+
startResponseExport: startResponseExport(options),
|
|
296
|
+
testConnection: testConnection(options)
|
|
146
297
|
});
|
|
147
298
|
// Annotate the CommonJS export names for ESM import in node:
|
|
148
299
|
0 && (module.exports = {
|
|
149
300
|
createConnection,
|
|
301
|
+
exportResponses,
|
|
150
302
|
getBearerToken,
|
|
303
|
+
getResponseExportFile,
|
|
304
|
+
getResponseExportProgress,
|
|
305
|
+
startResponseExport,
|
|
151
306
|
testConnection
|
|
152
307
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/utils.ts
|
|
1
|
+
// src/utils/index.ts
|
|
2
2
|
function success(data) {
|
|
3
3
|
return {
|
|
4
4
|
success: true,
|
|
@@ -14,12 +14,6 @@ function failure(error) {
|
|
|
14
14
|
function getErrorMessage(error) {
|
|
15
15
|
return error ? typeof error === "object" && "message" in error && typeof error.message === "string" ? error.message : error.toString() : "An error occured";
|
|
16
16
|
}
|
|
17
|
-
function safeParseBearerToken(response) {
|
|
18
|
-
return response?.access_token && typeof response.access_token === "string" ? success(response.access_token) : failure("Incorrect token format");
|
|
19
|
-
}
|
|
20
|
-
function safeParseTestResponse(response) {
|
|
21
|
-
return response?.result?.userId ? success(void 0) : failure("Incorrect test response format");
|
|
22
|
-
}
|
|
23
17
|
function getAuthHeaders(apiToken, bearerToken) {
|
|
24
18
|
if (apiToken)
|
|
25
19
|
return new Headers({
|
|
@@ -27,7 +21,7 @@ function getAuthHeaders(apiToken, bearerToken) {
|
|
|
27
21
|
});
|
|
28
22
|
if (bearerToken) {
|
|
29
23
|
return new Headers({
|
|
30
|
-
Authorization: bearerToken
|
|
24
|
+
Authorization: `Bearer ${bearerToken}`
|
|
31
25
|
});
|
|
32
26
|
}
|
|
33
27
|
throw new Error(
|
|
@@ -35,6 +29,82 @@ function getAuthHeaders(apiToken, bearerToken) {
|
|
|
35
29
|
);
|
|
36
30
|
}
|
|
37
31
|
|
|
32
|
+
// src/utils/poll.ts
|
|
33
|
+
async function poll({
|
|
34
|
+
fn,
|
|
35
|
+
validate,
|
|
36
|
+
interval,
|
|
37
|
+
maxAttempts
|
|
38
|
+
}) {
|
|
39
|
+
let attempts = 0;
|
|
40
|
+
const executePoll = async (resolve, reject) => {
|
|
41
|
+
try {
|
|
42
|
+
const result = await fn();
|
|
43
|
+
attempts++;
|
|
44
|
+
if (validate(result)) {
|
|
45
|
+
return resolve(result);
|
|
46
|
+
} else if (maxAttempts && attempts === maxAttempts) {
|
|
47
|
+
return reject(new Error("Exceeded max attempts"));
|
|
48
|
+
} else {
|
|
49
|
+
setTimeout(executePoll, interval, resolve, reject);
|
|
50
|
+
}
|
|
51
|
+
} catch (error) {
|
|
52
|
+
reject(new Error(`Poll function execution failed: ${error}`));
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
return new Promise(executePoll);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// src/methods/exportResponses.ts
|
|
59
|
+
var exportResponses = (connectionOptions) => async (responseOptions) => {
|
|
60
|
+
try {
|
|
61
|
+
const startResponseAction = startResponseExport(connectionOptions);
|
|
62
|
+
const startResponse = await startResponseAction(responseOptions);
|
|
63
|
+
if (!startResponse.success)
|
|
64
|
+
return failure(startResponse.error);
|
|
65
|
+
const exportProgressAction = getResponseExportProgress(connectionOptions);
|
|
66
|
+
const progressResponse = await poll({
|
|
67
|
+
fn: async () => await exportProgressAction({
|
|
68
|
+
exportProgressId: startResponse.data.progressId,
|
|
69
|
+
surveyId: responseOptions.surveyId,
|
|
70
|
+
bearerToken: responseOptions.bearerToken
|
|
71
|
+
}),
|
|
72
|
+
validate: (res) => res.success && res.data.percentComplete === 100,
|
|
73
|
+
interval: 1,
|
|
74
|
+
maxAttempts: 60
|
|
75
|
+
});
|
|
76
|
+
if (!progressResponse.success)
|
|
77
|
+
return failure(progressResponse.error);
|
|
78
|
+
const getFileResponseAction = getResponseExportFile(connectionOptions);
|
|
79
|
+
const fileResponse = await getFileResponseAction({
|
|
80
|
+
surveyId: responseOptions.surveyId,
|
|
81
|
+
fileId: progressResponse.data.fileId,
|
|
82
|
+
bearerToken: responseOptions.bearerToken
|
|
83
|
+
});
|
|
84
|
+
return fileResponse;
|
|
85
|
+
} catch (error) {
|
|
86
|
+
const message = getErrorMessage(error);
|
|
87
|
+
return failure(message);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// src/utils/parsers.ts
|
|
92
|
+
function safeParseBearerToken(response) {
|
|
93
|
+
return response?.access_token && typeof response.access_token === "string" ? success(response.access_token) : failure("Incorrect token format");
|
|
94
|
+
}
|
|
95
|
+
function safeParseTestResponse(response) {
|
|
96
|
+
return response?.result?.userId ? success(void 0) : failure("Incorrect test response format");
|
|
97
|
+
}
|
|
98
|
+
function safeParseStartFileExportResponse(response) {
|
|
99
|
+
return "result" in response ? "progressId" in response.result && "percentComplete" in response.result && "status" in response.result ? success(response.result) : failure("Start Export Response invalid format") : "error" in response ? failure(`${response.error.errorCode}: ${response.error.errorMessage}`) : failure(`Unable to parse Start Export Response`);
|
|
100
|
+
}
|
|
101
|
+
function safeParseFileProgressResponse(response) {
|
|
102
|
+
return "result" in response ? "fileId" in response.result && "percentComplete" in response.result && "status" in response.result ? success(response.result) : failure("File Progress Response invalid format") : "error" in response ? failure(`${response.error.errorCode}: ${response.error.errorMessage}`) : failure(`Unable to parse File Progress Response`);
|
|
103
|
+
}
|
|
104
|
+
function safeParseFileResponse(response) {
|
|
105
|
+
return Buffer.isBuffer(response) ? success(response) : failure("Incorrect file response format");
|
|
106
|
+
}
|
|
107
|
+
|
|
38
108
|
// src/qualtrics/index.ts
|
|
39
109
|
async function execute(config) {
|
|
40
110
|
const { datacenterId, route, headers, timeout, body } = config;
|
|
@@ -66,7 +136,7 @@ async function execute(config) {
|
|
|
66
136
|
}
|
|
67
137
|
|
|
68
138
|
// src/methods/getBearerToken.ts
|
|
69
|
-
var getBearerToken = (connectionOptions) => async ({ clientId, clientSecret }) => {
|
|
139
|
+
var getBearerToken = (connectionOptions) => async ({ clientId, clientSecret, scope }) => {
|
|
70
140
|
const route = `/oauth2/token`;
|
|
71
141
|
try {
|
|
72
142
|
const { datacenterId, timeout } = connectionOptions;
|
|
@@ -75,7 +145,7 @@ var getBearerToken = (connectionOptions) => async ({ clientId, clientSecret }) =
|
|
|
75
145
|
});
|
|
76
146
|
const body = new FormData();
|
|
77
147
|
body.append("grant_type", "client_credentials");
|
|
78
|
-
body.append("scope",
|
|
148
|
+
body.append("scope", scope);
|
|
79
149
|
const response = await execute({
|
|
80
150
|
datacenterId,
|
|
81
151
|
route,
|
|
@@ -91,6 +161,80 @@ var getBearerToken = (connectionOptions) => async ({ clientId, clientSecret }) =
|
|
|
91
161
|
}
|
|
92
162
|
};
|
|
93
163
|
|
|
164
|
+
// src/methods/getResponseExportProgress.ts
|
|
165
|
+
var getResponseExportProgress = (connectionOptions) => async ({ exportProgressId, surveyId, bearerToken }) => {
|
|
166
|
+
const route = `/surveys/${surveyId}/export-responses/${exportProgressId}`;
|
|
167
|
+
try {
|
|
168
|
+
const headers = getAuthHeaders(connectionOptions.apiToken, bearerToken);
|
|
169
|
+
const config = {
|
|
170
|
+
datacenterId: connectionOptions.datacenterId,
|
|
171
|
+
route,
|
|
172
|
+
headers,
|
|
173
|
+
timeout: connectionOptions.timeout
|
|
174
|
+
};
|
|
175
|
+
const response = await execute(config);
|
|
176
|
+
const result = safeParseFileProgressResponse(response);
|
|
177
|
+
return result;
|
|
178
|
+
} catch (error) {
|
|
179
|
+
const message = getErrorMessage(error);
|
|
180
|
+
return failure(message);
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// src/methods/getResponseExportFile.ts
|
|
185
|
+
var getResponseExportFile = (connectionOptions) => async ({ surveyId, fileId, bearerToken }) => {
|
|
186
|
+
const route = `/surveys/${surveyId}/export-responses/${fileId}/file`;
|
|
187
|
+
try {
|
|
188
|
+
const headers = getAuthHeaders(connectionOptions.apiToken, bearerToken);
|
|
189
|
+
const config = {
|
|
190
|
+
datacenterId: connectionOptions.datacenterId,
|
|
191
|
+
route,
|
|
192
|
+
headers,
|
|
193
|
+
timeout: connectionOptions.timeout
|
|
194
|
+
};
|
|
195
|
+
const response = await execute(config);
|
|
196
|
+
const result = safeParseFileResponse(response);
|
|
197
|
+
return result;
|
|
198
|
+
} catch (error) {
|
|
199
|
+
const message = getErrorMessage(error);
|
|
200
|
+
return failure(message);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
// src/methods/startResponseExport.ts
|
|
205
|
+
var startResponseExport = (connectionOptions) => async ({
|
|
206
|
+
surveyId,
|
|
207
|
+
startDate,
|
|
208
|
+
endDate,
|
|
209
|
+
format = "csv",
|
|
210
|
+
bearerToken = void 0,
|
|
211
|
+
...rest
|
|
212
|
+
}) => {
|
|
213
|
+
const route = `/surveys/${surveyId}/export-responses`;
|
|
214
|
+
try {
|
|
215
|
+
const headers = getAuthHeaders(connectionOptions.apiToken, bearerToken);
|
|
216
|
+
const body = JSON.stringify({
|
|
217
|
+
startDate: startDate.toISOString(),
|
|
218
|
+
endDate: endDate.toDateString(),
|
|
219
|
+
format,
|
|
220
|
+
...rest
|
|
221
|
+
});
|
|
222
|
+
const config = {
|
|
223
|
+
datacenterId: connectionOptions.datacenterId,
|
|
224
|
+
route,
|
|
225
|
+
headers,
|
|
226
|
+
body,
|
|
227
|
+
timeout: connectionOptions.timeout
|
|
228
|
+
};
|
|
229
|
+
const response = await execute(config);
|
|
230
|
+
const result = safeParseStartFileExportResponse(response);
|
|
231
|
+
return result;
|
|
232
|
+
} catch (error) {
|
|
233
|
+
const message = getErrorMessage(error);
|
|
234
|
+
return failure(message);
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
94
238
|
// src/methods/testConnection.ts
|
|
95
239
|
var testConnection = (connectionOptions) => async (bearerToken) => {
|
|
96
240
|
const route = "/API/v3/whoami";
|
|
@@ -113,11 +257,18 @@ var testConnection = (connectionOptions) => async (bearerToken) => {
|
|
|
113
257
|
|
|
114
258
|
// src/createConnection.ts
|
|
115
259
|
var createConnection = (options) => ({
|
|
116
|
-
|
|
117
|
-
getBearerToken: getBearerToken(options)
|
|
260
|
+
exportResponses: exportResponses(options),
|
|
261
|
+
getBearerToken: getBearerToken(options),
|
|
262
|
+
getResponseExportProgress: getResponseExportProgress(options),
|
|
263
|
+
startResponseExport: startResponseExport(options),
|
|
264
|
+
testConnection: testConnection(options)
|
|
118
265
|
});
|
|
119
266
|
export {
|
|
120
267
|
createConnection,
|
|
268
|
+
exportResponses,
|
|
121
269
|
getBearerToken,
|
|
270
|
+
getResponseExportFile,
|
|
271
|
+
getResponseExportProgress,
|
|
272
|
+
startResponseExport,
|
|
122
273
|
testConnection
|
|
123
274
|
};
|
package/package.json
CHANGED
package/tests/utils.test.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { success, failure } from '../src/utils'
|
|
2
3
|
import {
|
|
3
|
-
success,
|
|
4
|
-
failure,
|
|
5
4
|
safeParseBearerToken,
|
|
6
5
|
safeParseTestResponse,
|
|
7
|
-
|
|
6
|
+
safeParseStartFileExportResponse,
|
|
7
|
+
safeParseFileProgressResponse,
|
|
8
|
+
safeParseFileResponse,
|
|
9
|
+
} from '../src/utils/parsers'
|
|
8
10
|
|
|
9
11
|
describe('safeParseBearerToken', () => {
|
|
10
12
|
const fixture = {
|
|
@@ -29,6 +31,92 @@ describe('safeParseBearerToken', () => {
|
|
|
29
31
|
})
|
|
30
32
|
})
|
|
31
33
|
|
|
34
|
+
describe('safeParseFileProgressResponse', () => {
|
|
35
|
+
const fixture = {
|
|
36
|
+
result: {
|
|
37
|
+
fileId: 'sometoken',
|
|
38
|
+
percentComplete: 0,
|
|
39
|
+
status: 'inProgress',
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
it('should pass with correct data', () => {
|
|
44
|
+
const res = fixture
|
|
45
|
+
const expected = success(fixture.result)
|
|
46
|
+
const parsed = safeParseFileProgressResponse(res)
|
|
47
|
+
expect(parsed).toStrictEqual(expected)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('should fail when error response', () => {
|
|
51
|
+
const res = {
|
|
52
|
+
error: {
|
|
53
|
+
errorCode: '401',
|
|
54
|
+
errorMessage: 'Some error',
|
|
55
|
+
},
|
|
56
|
+
}
|
|
57
|
+
const expected = failure(
|
|
58
|
+
`${res.error.errorCode}: ${res.error.errorMessage}`
|
|
59
|
+
)
|
|
60
|
+
const parsed = safeParseFileProgressResponse(res)
|
|
61
|
+
expect(parsed).toStrictEqual(expected)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it('should fail with missing props', () => {
|
|
65
|
+
const res = {
|
|
66
|
+
result: {
|
|
67
|
+
percentComplete: 0,
|
|
68
|
+
status: 'inProgress',
|
|
69
|
+
},
|
|
70
|
+
}
|
|
71
|
+
const expected = failure('File Progress Response invalid format')
|
|
72
|
+
const parsed = safeParseFileProgressResponse(res)
|
|
73
|
+
expect(parsed).toStrictEqual(expected)
|
|
74
|
+
})
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
describe('safeParseStartFileExportResponse', () => {
|
|
78
|
+
const fixture = {
|
|
79
|
+
result: {
|
|
80
|
+
progressId: 'sometoken',
|
|
81
|
+
percentComplete: 0,
|
|
82
|
+
status: 'inProgress',
|
|
83
|
+
},
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
it('should pass with correct data', () => {
|
|
87
|
+
const res = fixture
|
|
88
|
+
const expected = success(fixture.result)
|
|
89
|
+
const parsed = safeParseStartFileExportResponse(res)
|
|
90
|
+
expect(parsed).toStrictEqual(expected)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
it('should fail when error response', () => {
|
|
94
|
+
const res = {
|
|
95
|
+
error: {
|
|
96
|
+
errorCode: '401',
|
|
97
|
+
errorMessage: 'Some error',
|
|
98
|
+
},
|
|
99
|
+
}
|
|
100
|
+
const expected = failure(
|
|
101
|
+
`${res.error.errorCode}: ${res.error.errorMessage}`
|
|
102
|
+
)
|
|
103
|
+
const parsed = safeParseStartFileExportResponse(res)
|
|
104
|
+
expect(parsed).toStrictEqual(expected)
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it('should fail with missing props', () => {
|
|
108
|
+
const res = {
|
|
109
|
+
result: {
|
|
110
|
+
percentComplete: 0,
|
|
111
|
+
status: 'inProgress',
|
|
112
|
+
},
|
|
113
|
+
}
|
|
114
|
+
const expected = failure('Start Export Response invalid format')
|
|
115
|
+
const parsed = safeParseStartFileExportResponse(res)
|
|
116
|
+
expect(parsed).toStrictEqual(expected)
|
|
117
|
+
})
|
|
118
|
+
})
|
|
119
|
+
|
|
32
120
|
describe('safeParseTestResponse', () => {
|
|
33
121
|
const fixture = {
|
|
34
122
|
result: {
|
|
@@ -52,3 +140,21 @@ describe('safeParseTestResponse', () => {
|
|
|
52
140
|
expect(parsed).toStrictEqual(expected)
|
|
53
141
|
})
|
|
54
142
|
})
|
|
143
|
+
|
|
144
|
+
describe('safeParseFileResponse', () => {
|
|
145
|
+
const fixture = Buffer.from('file content')
|
|
146
|
+
|
|
147
|
+
it('should pass with correct data', () => {
|
|
148
|
+
const res = fixture
|
|
149
|
+
const expected = success(fixture)
|
|
150
|
+
const parsed = safeParseFileResponse(res)
|
|
151
|
+
expect(parsed).toStrictEqual(expected)
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
it('should fail with invalid response type', () => {
|
|
155
|
+
const res = { fixture }
|
|
156
|
+
const expected = failure('Incorrect file response format')
|
|
157
|
+
const parsed = safeParseFileResponse(res)
|
|
158
|
+
expect(parsed).toStrictEqual(expected)
|
|
159
|
+
})
|
|
160
|
+
})
|