Skip to content

Commit 0ed210b

Browse files
committed
wip
1 parent aaa29d6 commit 0ed210b

File tree

9 files changed

+154
-23
lines changed

9 files changed

+154
-23
lines changed

packages/signals/signals-integration-tests/src/helpers/network-utils.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,38 @@ export class PageNetworkUtils {
5656
await req
5757
return responseBody
5858
}
59+
async makeFileUploadRequest(url: string) {
60+
let normalizeUrl = url
61+
if (url.startsWith('/')) {
62+
normalizeUrl = new URL(url, this.page.url()).href
63+
}
64+
const req = this.page.waitForResponse(normalizeUrl ?? url, {
65+
timeout: this.defaultResponseTimeout,
66+
})
67+
await this.page.evaluate((_url) => {
68+
const formData = new FormData()
69+
const file = new File(['file content'], 'test.txt', {
70+
type: 'text/plain',
71+
})
72+
formData.append('file', file)
73+
return fetch(_url, {
74+
method: 'POST',
75+
body: formData,
76+
headers: {
77+
'Content-Type': 'multipart/form-data',
78+
},
79+
})
80+
}, normalizeUrl)
81+
await req
82+
}
5983
/**
6084
* Make a fetch call in the page context. By default it will POST a JSON object with {foo: 'bar'}
6185
*/
6286
async makeFetchCall(
6387
url = this.defaultTestApiURL,
6488
request: Partial<RequestInit> & {
6589
contentType?: string
90+
blob?: boolean
6691
} = {}
6792
): Promise<any> {
6893
let normalizeUrl = url

packages/signals/signals-integration-tests/src/tests/signals-vanilla/network-signals-fetch.test.ts

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,62 @@ test.describe('network signals - fetch', () => {
1111
await indexPage.loadAndWait(page, basicEdgeFn)
1212
})
1313

14-
test('should not emit anything if neither request nor response are json', async () => {
14+
test('should not emit non-json requests without the body', async () => {
15+
await indexPage.network.mockTestRoute('http://localhost/upload', {
16+
body: JSON.stringify({ foo: 'test' }),
17+
})
18+
19+
await indexPage.network.makeFileUploadRequest('http://localhost/upload')
20+
21+
await indexPage.waitForSignalsApiFlush()
22+
23+
const networkEvents = indexPage.signalsAPI.getEvents('network')
24+
25+
// Check the request
26+
const requests = networkEvents.filter(
27+
(el) => el.properties!.data.action === 'request'
28+
)
29+
30+
expect(requests).toHaveLength(1)
31+
expect(requests[0].properties!.data.url).toBe('http://localhost/upload')
32+
expect(requests[0].properties!.data.data).toBeNull()
33+
})
34+
35+
test('should handle text/plain', async () => {
1536
await indexPage.network.mockTestRoute('http://localhost/test', {
16-
body: 'hello',
37+
body: JSON.stringify({ foo: 'test' }),
38+
contentType: 'application/json',
39+
})
40+
41+
await indexPage.network.makeFetchCall('http://localhost/test', {
42+
method: 'POST',
43+
body: JSON.stringify({ key: 'value' }),
1744
contentType: 'text/plain',
1845
})
1946

47+
await indexPage.waitForSignalsApiFlush()
48+
49+
const networkEvents = indexPage.signalsAPI.getEvents('network')
50+
51+
// Check the request
52+
const requests = networkEvents.filter(
53+
(el) => el.properties!.data.action === 'request'
54+
)
55+
56+
expect(requests).toHaveLength(1)
57+
expect(requests[0].properties!.data).toMatchObject({
58+
action: 'request',
59+
url: 'http://localhost/test',
60+
data: { key: 'value' },
61+
})
62+
})
63+
64+
test('should send the body as string if it cant be parsed to json', async () => {
65+
await indexPage.network.mockTestRoute('http://localhost/test', {
66+
body: JSON.stringify({ foo: 'test' }),
67+
contentType: 'application/json',
68+
})
69+
2070
await indexPage.network.makeFetchCall('http://localhost/test', {
2171
method: 'POST',
2272
body: 'hello world',
@@ -27,7 +77,17 @@ test.describe('network signals - fetch', () => {
2777

2878
const networkEvents = indexPage.signalsAPI.getEvents('network')
2979

30-
expect(networkEvents).toHaveLength(0)
80+
// Check the request
81+
const requests = networkEvents.filter(
82+
(el) => el.properties!.data.action === 'request'
83+
)
84+
85+
expect(requests).toHaveLength(1)
86+
expect(requests[0].properties!.data).toMatchObject({
87+
action: 'request',
88+
url: 'http://localhost/test',
89+
data: 'hello world',
90+
})
3191
})
3292

3393
test('can make a basic json request / not break regular fetch calls', async () => {

packages/signals/signals-integration-tests/src/tests/signals-vanilla/network-signals-xhr.test.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ test.describe('network signals - XHR', () => {
116116
})
117117
})
118118

119-
test('should emit response but not request if request content-type is not json but response is', async () => {
119+
test('should emit request content type, even if not json', async () => {
120120
await indexPage.network.mockTestRoute('http://localhost/test', {
121121
body: JSON.stringify({ foo: 'test' }),
122122
contentType: 'application/json',
@@ -134,7 +134,18 @@ test.describe('network signals - XHR', () => {
134134

135135
const networkEvents = indexPage.signalsAPI.getEvents('network')
136136

137-
// Check the response (only response should be captured)
137+
// ensure request
138+
const requests = networkEvents.filter(
139+
(el) => el.properties!.data.action === 'request'
140+
)
141+
expect(requests).toHaveLength(1)
142+
expect(requests[0].properties!.data).toMatchObject({
143+
action: 'request',
144+
url: 'http://localhost/test',
145+
data: 'hello world',
146+
})
147+
148+
// Check the response
138149
const responses = networkEvents.filter(
139150
(el) => el.properties!.data.action === 'response'
140151
)
@@ -144,12 +155,6 @@ test.describe('network signals - XHR', () => {
144155
url: 'http://localhost/test',
145156
data: { foo: 'test' },
146157
})
147-
148-
// Ensure no request was captured
149-
const requests = networkEvents.filter(
150-
(el) => el.properties!.data.action === 'request'
151-
)
152-
expect(requests).toHaveLength(0)
153158
})
154159

155160
test('should parse response if responseType is set to json but response header does not contain application/json', async () => {

packages/signals/signals/src/core/signal-generators/network-gen/__tests__/helpers.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,13 @@ describe(containsContentType, () => {
9999
'application/json',
100100
])
101101
).toBe(true)
102+
103+
expect(
104+
containsContentType(
105+
new Headers({ 'Content-Type': 'application/json ; charset=utf-8' }),
106+
['application/json']
107+
)
108+
).toBe(true)
102109
})
103110

104111
it('should return false if headers do not contain application/json', () => {

packages/signals/signals/src/core/signal-generators/network-gen/__tests__/network-generator.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,29 @@ describe(NetworkGenerator, () => {
142142
await sleep(100)
143143
expect(mockEmitter.emit.mock.calls).toMatchInlineSnapshot(`
144144
[
145+
[
146+
{
147+
"data": {
148+
"action": "request",
149+
"contentType": "text/html",
150+
"data": "hello world",
151+
"method": "GET",
152+
"url": "http://localhost/api",
153+
},
154+
"metadata": {
155+
"filters": {
156+
"allowed": [],
157+
"disallowed": [],
158+
},
159+
},
160+
"type": "network",
161+
},
162+
],
145163
[
146164
{
147165
"data": {
148166
"action": "response",
167+
"contentType": "application/json",
149168
"data": {
150169
"data": "test",
151170
},
@@ -189,6 +208,7 @@ describe(NetworkGenerator, () => {
189208
{
190209
"data": {
191210
"action": "request",
211+
"contentType": "application/json",
192212
"data": {
193213
"key": "value",
194214
},
@@ -209,6 +229,7 @@ describe(NetworkGenerator, () => {
209229
{
210230
"data": {
211231
"action": "response",
232+
"contentType": "application/json",
212233
"data": {
213234
"data": "test",
214235
},

packages/signals/signals/src/core/signal-generators/network-gen/helpers.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,22 @@ export const containsContentType = (
4747
// format the content-type header to remove charset -- this is non-standard behavior that is somewhat common
4848
// e.g. application/json;charset=utf-8 => application/json
4949
const removeCharset = (header: string | null): string | null =>
50-
header?.split(';')[0] ?? null
50+
header?.split(';')[0].trim() ?? null
5151

52-
return match.some(
53-
(t) => removeCharset(normalizedHeaders.get('content-type')) === t
52+
return match.some((t) =>
53+
removeCharset(normalizedHeaders.get('content-type'))?.includes(t)
5454
)
5555
}
5656

57-
export const containsJSONContentType = (
57+
export const containsJSONParseableContentType = (
5858
headers: HeadersInit | undefined
5959
): boolean => {
60-
return containsContentType(headers, ['application/json'])
60+
return containsContentType(headers, [
61+
'application/json',
62+
'application/ld+json',
63+
'text/plain',
64+
'text/json',
65+
])
6166
}
6267

6368
export function isPlainObject(obj: unknown): obj is Record<string, unknown> {

packages/signals/signals/src/core/signal-generators/network-gen/index.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
NetworkRequestHandler,
1313
NetworkResponseHandler,
1414
} from './network-interceptor'
15-
import { containsJSONContentType } from './helpers'
15+
import { containsJSONParseableContentType, tryJSONParse } from './helpers'
1616

1717
export type NetworkSettingsConfigSettings = Pick<
1818
SignalsSettingsConfig,
@@ -52,22 +52,23 @@ export class NetworkGenerator implements SignalGenerator {
5252
const createMetadata = () => ({
5353
filters: this.filter.settings.networkSignalsFilterList.getRegexes(),
5454
})
55-
const handleRequest: NetworkRequestHandler = (rq) => {
56-
if (!containsJSONContentType(rq.headers)) {
57-
return
58-
}
5955

56+
const handleRequest: NetworkRequestHandler = (rq) => {
6057
if (!rq.url || !this.filter.isAllowed(rq.url)) {
6158
return
6259
}
60+
61+
const data = typeof rq.body === 'string' ? tryJSONParse(rq.body) : null
62+
6363
this.emittedRequestIds.push(rq.id)
6464
emitter.emit(
6565
createNetworkSignal(
6666
{
6767
action: 'request',
6868
url: rq.url,
6969
method: rq.method || 'GET',
70-
data: rq.body ? JSON.parse(rq.body.toString()) : null,
70+
data,
71+
contentType: rq.headers?.get('content-type') || '',
7172
},
7273
createMetadata()
7374
)
@@ -78,7 +79,7 @@ export class NetworkGenerator implements SignalGenerator {
7879
const isSuccessWithNonJSONResponse =
7980
rs.ok &&
8081
rs.responseType !== 'json' &&
81-
!containsJSONContentType(rs.headers)
82+
!containsJSONParseableContentType(rs.headers)
8283

8384
const isErrorButRequestNeverEmittted =
8485
!rs.ok && !this.emittedRequestIds.includes(rs.req.id)
@@ -101,6 +102,7 @@ export class NetworkGenerator implements SignalGenerator {
101102
data: data,
102103
ok: rs.ok,
103104
status: rs.status,
105+
contentType: rs.headers.get('content-type') || '',
104106
},
105107
createMetadata()
106108
)

packages/signals/signals/src/types/__tests__/create-network-signal.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ describe(createNetworkSignal, () => {
2323
url: 'http://example.com',
2424
method: 'post',
2525
data: { key: 'value' },
26+
contentType: 'application/json',
2627
}
2728

2829
const signal = createNetworkSignal(data, metadata)
@@ -31,6 +32,7 @@ describe(createNetworkSignal, () => {
3132
{
3233
"data": {
3334
"action": "request",
35+
"contentType": "application/json",
3436
"data": {
3537
"key": "value",
3638
},
@@ -61,6 +63,7 @@ describe(createNetworkSignal, () => {
6163
url: 'http://example.com',
6264
ok: true,
6365
status: 200,
66+
contentType: 'application/json',
6467
data: { key: 'value' },
6568
}
6669

@@ -70,6 +73,7 @@ describe(createNetworkSignal, () => {
7073
{
7174
"data": {
7275
"action": "response",
76+
"contentType": "application/json",
7377
"data": {
7478
"key": "value",
7579
},

packages/signals/signals/src/types/signals.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,15 @@ interface NetworkRequestData extends BaseNetworkData {
8484
action: 'request'
8585
url: string
8686
method: string
87+
contentType: string
8788
}
8889

8990
interface NetworkResponseData extends BaseNetworkData {
9091
action: 'response'
9192
url: string
9293
status: number
9394
ok: boolean
95+
contentType: string
9496
}
9597

9698
export type NetworkData = NetworkRequestData | NetworkResponseData

0 commit comments

Comments
 (0)