Skip to content

Commit

Permalink
add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
wangcheng committed Dec 3, 2024
1 parent 2920e45 commit 7587ff7
Show file tree
Hide file tree
Showing 3 changed files with 273 additions and 5 deletions.
31 changes: 31 additions & 0 deletions packages/connect-miniprogram/src/connect/async-generator.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { describe, expect, jest, test } from '@jest/globals';

import { createAsyncGeneratorFromEventPattern } from './async-generator';

describe('createAsyncGeneratorFromEventPattern', () => {
const dispose = jest.fn();
test('creates am async generator', async () => {
const gen = createAsyncGeneratorFromEventPattern<number>(
({ handleValue, handleEnd }) => {
setTimeout(() => {
handleValue(1);
setTimeout(() => {
handleValue(2);
setTimeout(() => {
handleEnd();
}, 0);
}, 0);
}, 0);
return dispose;
},
);
const a = gen();
expect(dispose).toBeCalledTimes(0);
expect(await a.next()).toEqual({ value: 1, done: false });
expect(dispose).toBeCalledTimes(0);
expect(await a.next()).toEqual({ value: 2, done: false });
expect(dispose).toBeCalledTimes(0);
expect(await a.next()).toEqual({ value: undefined, done: true });
expect(dispose).toBeCalledTimes(1);
});
});
230 changes: 230 additions & 0 deletions packages/connect-miniprogram/src/connect/wx-request.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
import { describe, expect, jest, test } from '@jest/globals';

import {
createWxRequestAsAsyncGenerator,
createWxRequestAsPromise,
} from './wx-request';

jest.mock('../protocol/envelope', () => ({
createEnvelopeAsyncGenerator: (s) => s,
}));

function typedArrayToBuffer(arr: Uint8Array) {
const length = arr.length;
const buffer = new ArrayBuffer(length);
const bufView = new Uint8Array(buffer);
for (let i = 0; i < length; i++) {
bufView[i] = arr[i];
}
return buffer;
}

const mockWxRequest = (noHeader: boolean = false) =>
jest.fn((options: WechatMiniprogram.RequestOption) => {
let chunkReceivedHandler: undefined | ((res: any) => void);
let headersReceivedHandler: undefined | ((res: any) => void);
const headerData: Partial<WechatMiniprogram.RequestSuccessCallbackResult> =
{
header: {
'response-header-key': 'response-header-value',
},
statusCode: 200,
cookies: [],
};
if (options.enableChunked) {
setTimeout(() => {
if (!noHeader) {
headersReceivedHandler?.(headerData);
}
setTimeout(() => {
chunkReceivedHandler?.({
data: typedArrayToBuffer(new Uint8Array([1, 2, 3])),
});
setTimeout(() => {
chunkReceivedHandler?.({
data: typedArrayToBuffer(new Uint8Array([4, 5, 6])),
});
options.success?.(
{} as WechatMiniprogram.RequestSuccessCallbackResult,
);
}, 0);
}, 0);
}, 0);
} else {
setTimeout(() => {
options.success?.({
...headerData,
data: typedArrayToBuffer(new Uint8Array([1, 2, 3, 4, 5, 6])),
} as WechatMiniprogram.RequestSuccessCallbackResult);
}, 0);
}
return {
abort: jest.fn(),
onChunkReceived: jest.fn((fn: (res: any) => void) => {
chunkReceivedHandler = fn;
}),
offChunkReceived: jest.fn(() => {
chunkReceivedHandler = undefined;
}),
onHeadersReceived: jest.fn((fn: (res: any) => void) => {
headersReceivedHandler = fn;
}),
offHeadersReceived: jest.fn(() => {
headersReceivedHandler = undefined;
}),
} as WechatMiniprogram.RequestTask;
}) as typeof wx.request;

describe('createWxRequestAsPromise', () => {
test('should return a promise, using binary format', () => {
const wxRequest = mockWxRequest();
const request = createWxRequestAsPromise(
{
request: wxRequest,
requestOptions: {
forceCellularNetwork: true,
},
},
true,
);
const header = new Headers();
header.append('foo', 'bar');
request({
url: 'https://example.com',
data: 'data',
method: 'POST',
header,
});
expect(wxRequest).toBeCalledWith({
url: 'https://example.com',
data: 'data',
method: 'POST',
header: {
foo: 'bar',
},
responseType: 'arraybuffer',
forceCellularNetwork: true,
fail: expect.any(Function),
success: expect.any(Function),
});
});
});

describe('createWxRequestAsAsyncGenerator', () => {
test('should return an async generator, not devtool', async () => {
const wxRequest = mockWxRequest();
const request = createWxRequestAsAsyncGenerator({
request: wxRequest,
isDevTool: false,
requestOptions: {
forceCellularNetwork: true,
},
});
const reqHeaders = new Headers();
reqHeaders.append('foo', 'bar');
const {
header: resHeader,
statusCode,
messageStream,
} = await request({
url: 'https://example.com',
data: 'data',
method: 'POST',
header: reqHeaders,
});
expect(wxRequest).toBeCalledWith({
url: 'https://example.com',
data: 'data',
method: 'POST',
header: {
foo: 'bar',
},
enableChunked: true,
responseType: 'arraybuffer',
forceCellularNetwork: true,
fail: expect.any(Function),
success: expect.any(Function),
});

expect(resHeader.get('response-header-key')).toBe('response-header-value');
expect(statusCode).toBe(200);
expect(await messageStream.next()).toEqual({
done: false,
value: new Uint8Array([1, 2, 3]),
});
expect(await messageStream.next()).toEqual({
done: false,
value: new Uint8Array([4, 5, 6]),
});
expect(await messageStream.next()).toEqual({
done: true,
value: undefined,
});
});

test('should return an async generator, is devtool', async () => {
const wxRequest = mockWxRequest();
const request = createWxRequestAsAsyncGenerator({
request: wxRequest,
isDevTool: true,
requestOptions: {
forceCellularNetwork: true,
},
});
const reqHeaders = new Headers();
reqHeaders.append('foo', 'bar');
const {
header: resHeader,
statusCode,
messageStream,
} = await request({
url: 'https://example.com',
data: 'data',
method: 'POST',
header: reqHeaders,
});
expect(wxRequest).toBeCalledWith({
url: 'https://example.com',
data: 'data',
method: 'POST',
header: {
foo: 'bar',
},
responseType: 'arraybuffer',
forceCellularNetwork: true,
fail: expect.any(Function),
success: expect.any(Function),
});
expect(resHeader.get('response-header-key')).toBe('response-header-value');
expect(statusCode).toBe(200);
expect(await messageStream.next()).toEqual({
done: false,
value: new Uint8Array([1, 2, 3, 4, 5, 6]),
});
expect(await messageStream.next()).toEqual({
done: true,
value: undefined,
});
});

test('should throw if first chunk is not header', async () => {
const wxRequest = mockWxRequest(true);
const request = createWxRequestAsAsyncGenerator({
request: wxRequest,
isDevTool: false,
requestOptions: {
forceCellularNetwork: true,
},
});
const reqHeaders = new Headers();
reqHeaders.append('foo', 'bar');
expect(async () => {
await request({
url: 'https://example.com',
data: 'data',
method: 'POST',
header: reqHeaders,
});
}).rejects.toThrow('missing header');
});
});
17 changes: 12 additions & 5 deletions packages/connect-miniprogram/src/connect/wx-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,12 @@ function create(
}

async function demuxStream(iterator: AsyncGenerator<RequestEvent>) {
const firstChunk = await iterator.next();
if (firstChunk.done || firstChunk.value.name !== 'HeadersReceived') {
throw new Error('missing header');
}
// first value is header
const headerChunk = (await iterator.next()).value as HeadersReceivedEvent;
const { statusCode, header } = firstChunk.value.payload;

async function* messageStream() {
for await (const value of iterator) {
Expand All @@ -123,8 +127,8 @@ async function demuxStream(iterator: AsyncGenerator<RequestEvent>) {
}

return {
statusCode: headerChunk.payload.statusCode,
header: new Headers(headerChunk?.payload.header),
statusCode: statusCode,
header: new Headers(header),
messageStream: createEnvelopeAsyncGenerator(messageStream()),
};
}
Expand All @@ -133,7 +137,7 @@ export function createWxRequestAsAsyncGenerator({
request,
isDevTool,
requestOptions,
}: CreateTransportOptions) {
}: Pick<CreateTransportOptions, 'request' | 'isDevTool' | 'requestOptions'>) {
/**
* Weixin devtool has a bug if enableChunked is true.
* https://developers.weixin.qq.com/community/develop/doc/000e44fc464560a0a6bf4188f56800
Expand All @@ -145,7 +149,10 @@ export function createWxRequestAsAsyncGenerator({
}

export function createWxRequestAsPromise(
{ request, requestOptions }: CreateTransportOptions,
{
request,
requestOptions,
}: Pick<CreateTransportOptions, 'request' | 'requestOptions'>,
useBinaryFormat: boolean,
) {
return (options: PartialOptions) =>
Expand Down

0 comments on commit 7587ff7

Please sign in to comment.