Skip to content

Commit

Permalink
add tests
Browse files Browse the repository at this point in the history
add tests
  • Loading branch information
wangcheng committed Dec 3, 2024
1 parent 2920e45 commit 529117e
Show file tree
Hide file tree
Showing 5 changed files with 311 additions and 5 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"packages/example-mina"
],
"scripts": {
"test": "yarn workspace connect-miniprogram jest",
"build": "yarn workspace connect-miniprogram build",
"dev:taro": "yarn workspace example-taro dev:weapp"
},
Expand Down
39 changes: 39 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,39 @@
import { describe, expect, jest, test } from '@jest/globals';

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

describe('createAsyncGeneratorFromEventPattern', () => {
const dispose = jest.fn();
test('creates am async generator', async () => {
const gen = createAsyncGeneratorFromEventPattern<number>(
({ handleValue, handleEnd }) => {
fireEventQueue([
() => {
handleValue(0);
},
() => {
handleValue(1);
},
() => {
handleValue(2);
},
() => {
handleEnd();
},
]);
return dispose;
},
);
const a = gen();
expect(dispose).toBeCalledTimes(0);
expect(await a.next()).toEqual({ value: 0, done: false });
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);
});
});
175 changes: 175 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,175 @@
import { describe, expect, jest, test } from '@jest/globals';

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

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

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({
responseHeader: {
'response-header-key': 'response-header-value',
},
});
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({
responseHeader: {
'response-header-key': 'response-header-value',
},
});
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({
skipHeadersReceivedHandler: 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
84 changes: 84 additions & 0 deletions packages/connect-miniprogram/src/test-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { jest } from '@jest/globals';

function wait() {
return new Promise((resolve) => setTimeout(resolve, 0));
}

export async function fireEventQueue(fns: (() => void)[]) {
for (const fn of fns) {
await wait();
fn();
}
}

function buffer(arr: number[]) {
return new Uint8Array(arr).buffer;
}

export const mockWxRequest = ({
responseHeader = {},
skipHeadersReceivedHandler = false,
}: {
responseHeader?: Record<string, string>;
skipHeadersReceivedHandler?: boolean;
}) => {
const headerData: Partial<WechatMiniprogram.RequestSuccessCallbackResult> = {
header: responseHeader,
statusCode: 200,
cookies: [],
};
return jest.fn((options: WechatMiniprogram.RequestOption) => {
let chunkReceivedHandler: undefined | ((res: any) => void);
let headersReceivedHandler: undefined | ((res: any) => void);

if (options.enableChunked) {
const eventQueue = [
() => {
if (!skipHeadersReceivedHandler) {
headersReceivedHandler?.(headerData);
}
},
() => {
chunkReceivedHandler?.({
data: buffer([1, 2, 3]),
});
},
() => {
chunkReceivedHandler?.({
data: buffer([4, 5, 6]),
});
},
() => {
options.success?.(
{} as WechatMiniprogram.RequestSuccessCallbackResult,
);
},
];
fireEventQueue(eventQueue);
} else {
fireEventQueue([
() => {
options.success?.({
...headerData,
data: buffer([1, 2, 3, 4, 5, 6]),
} as WechatMiniprogram.RequestSuccessCallbackResult);
},
]);
}
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;
};

0 comments on commit 529117e

Please sign in to comment.