Skip to content

Commit 9bdd6b3

Browse files
authored
Merge pull request #8 from taktik/feature/upload-progress
Add upload progress notification on request
2 parents 53fe285 + 4892dda commit 9bdd6b3

File tree

5 files changed

+174
-89
lines changed

5 files changed

+174
-89
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"scripts": {
1818
"prepublish": "npm run build",
1919
"build": "npm run tslint && tsc",
20-
"tslint": "tslint src/*",
20+
"tslint": "tslint --project tsconfig.json --config tslint.json",
2121
"test:debug": "karma start",
2222
"test": "karma start --single-run"
2323
},

src/execute.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ export default function execute<T>(request: httpclient.Request): Promise<httpcli
3737
request.xhr = xhr
3838
xhr.withCredentials = request.withCredentials
3939
xhr.timeout = request.timeout
40+
xhr.upload.onloadstart = request.upload.onloadstart
41+
xhr.upload.onprogress = request.upload.onprogress
4042

4143
// This internal method takes the xml request and retrieves headers from it
4244
const parseResponseHeaders = function(request: XMLHttpRequest): httpclient.Headers {

src/index.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ export namespace httpclient {
9797
}
9898
this.aborted = true
9999
}
100+
upload: {
101+
onprogress: { (event: Event): void }
102+
onloadstart: { (event: Event): void }
103+
}
100104
url: string
101105
contentType: string = 'application/json; charset=UTF-8'
102106
// A way to declare an enumeration (can be anything because of the string but the IDE will suggest the 4 first verbs)
@@ -139,6 +143,10 @@ export namespace httpclient {
139143
if (timeout) {
140144
this.timeout = timeout
141145
}
146+
this.upload = {
147+
onprogress: () => void 0,
148+
onloadstart: () => void 0
149+
}
142150
}
143151

144152
// sets the properties (like a constructor for changes)
@@ -275,7 +283,7 @@ export namespace httpclient {
275283
* nested filters. So it contains an array of filter and its doFilter loops through all its filters
276284
* before continuing with the main chain of filters
277285
*/
278-
doFilter (call: httpclient.Request, filterChain: httpclient.FilterChain<any>): Promise<httpclient.Response<any>> {
286+
doFilter (call: Request, filterChain: FilterChain<any>): Promise<Response<any>> {
279287
return new FilterChainImpl(this.filters, 0, request => filterChain.doFilter(request)).doFilter(call)
280288
}
281289
}
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import { assert } from 'chai'
2+
import execute from '../src/execute'
3+
import { httpclient } from '../src/index'
4+
import sinon, { SinonFakeServer } from 'sinon'
5+
6+
describe('execute', function() {
7+
let server: SinonFakeServer
8+
describe('execute with a real API external', function() {
9+
before(function() {
10+
server = sinon.fakeServer.create()
11+
})
12+
after(function() {
13+
server.restore()
14+
})
15+
16+
it('should be able to create an entry', async function() {
17+
const aRequest = new httpclient.Request('http://dummy.restapiexample.com/api/v1/create')
18+
aRequest.method = 'POST'
19+
aRequest.body = {
20+
'name': 'auDD',
21+
'salary': '333000',
22+
'age': '22'
23+
}
24+
server.respondWith(
25+
'POST',
26+
'http://dummy.restapiexample.com/api/v1/create',
27+
[
28+
200,
29+
{ 'Content-Type': 'application/json' },
30+
JSON.stringify({ id: 'anID' })
31+
]
32+
)
33+
const postResponsePromises = execute(aRequest)
34+
server.respond()
35+
const postResponse = await postResponsePromises
36+
assert.equal((postResponse as any).status, 200)
37+
})
38+
it('should be able to find the entry we posted before', async function() {
39+
40+
server.respondWith(
41+
'GET',
42+
'http://dummy.restapiexample.com/api/v1/employees',
43+
[
44+
200,
45+
{ 'Content-Type': 'application/json' },
46+
JSON.stringify([ {
47+
'name': 'auDD',
48+
'salary': '333000',
49+
'age': '22'
50+
}])
51+
]
52+
)
53+
54+
const aRequest = new httpclient.Request('http://dummy.restapiexample.com/api/v1/employees')
55+
const postResponsePromises = execute<any[]>(aRequest)
56+
server.respond()
57+
const getResponse = await postResponsePromises
58+
const employees = getResponse.body
59+
assert.deepEqual(employees, [ {
60+
'name': 'auDD',
61+
'salary': '333000',
62+
'age': '22'
63+
}])
64+
})
65+
it('should be able to modify the entry we added', async function() {
66+
const expectedResponse = [ {
67+
'name': 'auDD',
68+
'salary': '333000',
69+
'age': '22'
70+
}]
71+
server.respondWith(
72+
'PUT',
73+
'http://dummy.restapiexample.com/api/v1/update/anID',
74+
[
75+
200,
76+
{ 'Content-Type': 'application/json' },
77+
JSON.stringify(expectedResponse)
78+
]
79+
)
80+
const aRequest = new httpclient.Request('http://dummy.restapiexample.com/api/v1/update/anID')
81+
aRequest.method = 'PUT'
82+
aRequest.body = {
83+
'name': 'pnl',
84+
'salary': '1000000',
85+
'age': '22'
86+
}
87+
const postResponsePromises = execute(aRequest)
88+
server.respond()
89+
const putResponse = await postResponsePromises
90+
assert.deepEqual(putResponse.body, expectedResponse)
91+
92+
})
93+
it('should be able to delete the entry we modified before', async function() {
94+
server.respondWith(
95+
'DELETE',
96+
'http://dummy.restapiexample.com/api/v1/delete/idOfCreatedObject',
97+
[
98+
200,
99+
{ 'Content-Type': 'application/json' },
100+
JSON.stringify({ expectedResponse: 'any' })
101+
]
102+
)
103+
const aRequest = new httpclient.Request('http://dummy.restapiexample.com/api/v1/delete/idOfCreatedObject')
104+
aRequest.method = 'DELETE'
105+
const postResponsePromises = execute(aRequest)
106+
server.respond()
107+
const response = await postResponsePromises
108+
//
109+
110+
assert.deepEqual(response.body, { expectedResponse: 'any' })
111+
112+
})
113+
it('should throw an error if http request sent to bad url', async function() {
114+
try {
115+
server.respondWith(
116+
'GET',
117+
'http://dummy.restapiexample.com/i@#ccidently_mizspeld976theurl/',
118+
[
119+
404,
120+
{ 'Content-Type': 'application/json' },
121+
'not found'
122+
]
123+
)
124+
const aRequest = new httpclient.Request('http://dummy.restapiexample.com/i@#ccidently_mizspeld976theurl/')
125+
const responsePromise = execute(aRequest)
126+
server.respond()
127+
const response = await responsePromise
128+
assert.isTrue(false, 'previous line should throw an error')
129+
} catch (error) {
130+
const response: httpclient.Response<Object> = error
131+
assert.equal(response.status, 404)
132+
}
133+
})
134+
it('should also throw an error on server error', async function() {
135+
try {
136+
server.respondWith(
137+
'PUT',
138+
'http://dummy.restapiexample.com/api/v1/employees',
139+
[
140+
500,
141+
{ 'Content-Type': 'application/json' },
142+
'server error'
143+
]
144+
)
145+
const aRequest = new httpclient.Request('http://dummy.restapiexample.com/api/v1/employees')
146+
aRequest.method = 'PUT'
147+
aRequest.body = {
148+
'name': 'pnl',
149+
'salary': '1000000',
150+
'age': '22'
151+
}
152+
const responsePromise = execute(aRequest)
153+
server.respond()
154+
const response = await responsePromise
155+
assert.isTrue(false, 'previous line should throw an error')
156+
} catch (error) {
157+
const response: httpclient.Response<Object> = error
158+
assert.equal(response.status,500)
159+
}
160+
})
161+
})
162+
})

test/test-unitaires-execute.ts

Lines changed: 0 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -78,91 +78,4 @@ describe('execute', function() {
7878
assert.equal(a.body, undefined)
7979
})
8080
})
81-
describe('execute with a real API external', function() {
82-
let postResponse: Object
83-
let idOfCreatedObject: number
84-
before(async function() {
85-
this.timeout(5000)
86-
aRequest = new httpclient.Request('http://dummy.restapiexample.com/api/v1/create')
87-
aRequest.method = 'POST'
88-
aRequest.body = {
89-
'name': 'auDD',
90-
'salary': '333000',
91-
'age': '22'
92-
}
93-
postResponse = await execute(aRequest)
94-
})
95-
it('should be able to create an entry', function() {
96-
assert.isAbove((postResponse as any).status, 199)
97-
assert.isBelow((postResponse as any).status, 300)
98-
})
99-
it('should be able to find the entry we posted before', async function() {
100-
this.timeout(5000)
101-
aRequest = new httpclient.Request('http://dummy.restapiexample.com/api/v1/employees')
102-
const getResponse = await execute(aRequest)
103-
let allEmployees = getResponse.body
104-
let theEmployee = (allEmployees as Array<Object>).find((k) => (k as any).employee_name === 'auDD')
105-
idOfCreatedObject = (theEmployee as any).id
106-
assert.equal((theEmployee as any).employee_salary,333000)
107-
assert.equal((theEmployee as any).employee_age,22)
108-
})
109-
it('should be able to modify the entry we added', async function() {
110-
this.timeout(5000)
111-
aRequest = new httpclient.Request('http://dummy.restapiexample.com/api/v1/update/' + idOfCreatedObject)
112-
aRequest.method = 'PUT'
113-
aRequest.body = {
114-
'name': 'pnl',
115-
'salary': '1000000',
116-
'age': '22'
117-
}
118-
let putResponse = await execute(aRequest)
119-
aRequest = new httpclient.Request('http://dummy.restapiexample.com/api/v1/employees')
120-
const getResponse = await execute(aRequest)
121-
let allEmployees = getResponse.body
122-
let theEmployee = (allEmployees as Array<Object>).find((k) => (k as any).employee_name === 'pnl')
123-
assert.equal(idOfCreatedObject,(theEmployee as any).id)
124-
assert.equal((theEmployee as any).employee_salary,1000000)
125-
assert.equal((theEmployee as any).employee_age,22)
126-
})
127-
it('should be able to delete the entry we modified before', async function() {
128-
this.timeout(5000)
129-
aRequest = new httpclient.Request('http://dummy.restapiexample.com/api/v1/delete/' + idOfCreatedObject)
130-
aRequest.method = 'DELETE'
131-
await execute(aRequest)
132-
//
133-
aRequest = new httpclient.Request('http://dummy.restapiexample.com/api/v1/employees')
134-
const getResponse = await execute(aRequest)
135-
let allEmployees = getResponse.body
136-
let theEmployee = (allEmployees as Array<Object>).find((k) => (k as any).id === idOfCreatedObject)
137-
assert.notExists(theEmployee)
138-
})
139-
it('should throw an error if http request sent to bad url', async function() {
140-
this.timeout(5000)
141-
try {
142-
aRequest = new httpclient.Request('i@#ccidently_mizspeld976theurl/')
143-
await execute(aRequest)
144-
assert.isTrue(false, 'previous line should throw an error')
145-
} catch (error) {
146-
const response: httpclient.Response<Object> = error
147-
assert.equal(response.status, 404)
148-
}
149-
})
150-
it('should also throw an error if the routing does not support the verb', async function() {
151-
this.timeout(5000)
152-
try {
153-
aRequest = new httpclient.Request('http://dummy.restapiexample.com/api/v1/employees')
154-
aRequest.method = 'PUT'
155-
aRequest.body = {
156-
'name': 'pnl',
157-
'salary': '1000000',
158-
'age': '22'
159-
}
160-
await execute(aRequest)
161-
assert.isTrue(false, 'previous line should throw an error')
162-
} catch (error) {
163-
const response: httpclient.Response<Object> = error
164-
assert.equal(response.status,405)
165-
}
166-
})
167-
})
16881
})

0 commit comments

Comments
 (0)