From d0411444a250f0aabf091c4cf35da0f9ca269ab7 Mon Sep 17 00:00:00 2001 From: MeetinaXD Date: Wed, 12 Jun 2024 21:44:54 +0800 Subject: [PATCH] fix(tests,linting): resolve test hanging and eslint warnings in useSSE --- packages/scene-react/test/useSSE.spec.tsx | 43 +++++++++++++---------- packages/scene-vue/test/useSSE.spec.ts | 33 ++++++++++------- src/hooks/useSSE.ts | 3 +- 3 files changed, 46 insertions(+), 33 deletions(-) diff --git a/packages/scene-react/test/useSSE.spec.tsx b/packages/scene-react/test/useSSE.spec.tsx index 884333a..a1c6073 100644 --- a/packages/scene-react/test/useSSE.spec.tsx +++ b/packages/scene-react/test/useSSE.spec.tsx @@ -1,7 +1,7 @@ import { undefinedValue } from '@/helper/variables'; import '@testing-library/jest-dom'; import { fireEvent, render, screen, waitFor } from '@testing-library/react'; -import { Alova, createAlova } from 'alova'; +import { createAlova } from 'alova'; import GlobalFetch from 'alova/GlobalFetch'; import ReactHook from 'alova/react'; import ES from 'eventsource'; @@ -9,13 +9,10 @@ import { AddressInfo } from 'net'; import React, { ReactElement } from 'react'; import { IntervalEventName, IntervalMessage, TriggerEventName, server, send as serverSend } from '~/test/sseServer'; import { getAlovaInstance, untilCbCalled } from '~/test/utils'; -import { FetchRequestInit } from '~/typings/general'; -import { ReactState, useSSE } from '..'; +import { useSSE } from '..'; import { AlovaSSEMessageEvent, SSEHookReadyState } from '../typings/general'; Object.defineProperty(global, 'EventSource', { value: ES, writable: false }); -let alovaInst: Alova, unknown, FetchRequestInit, any, any>; - afterEach(() => { server.close(); }); @@ -28,18 +25,18 @@ type AnyMessageType = AlovaSSEMessageEvent { await server.listen(); const { port } = server.address() as AddressInfo; - alovaInst = createAlova({ + return createAlova({ baseURL: `http://127.0.0.1:${port}`, statesHook: ReactHook, requestAdapter: GlobalFetch(), cacheLogger: false - }) as any; + }); }; describe('react => useSSE', () => { // ! 无初始数据,不立即发送请求 test('should default not request immediately', async () => { - await prepareAlova(); + const alovaInst = await prepareAlova(); const poster = (data: any) => alovaInst.Get(`/${IntervalEventName}`, data); let recv = undefinedValue; @@ -47,10 +44,9 @@ describe('react => useSSE', () => { const mockOnFn = jest.fn((event: AnyMessageType) => { recv = event.data; }); - // const mockOpenFn = jest.fn(); const Page = () => { - const { on, onOpen, data, readyState, send } = useSSE(poster); + const { on, onOpen, data, readyState, send, close } = useSSE(poster); on(IntervalEventName, mockOnFn); onOpen(mockOpenFn); @@ -69,6 +65,11 @@ describe('react => useSSE', () => { onClick={send}> send request + ); }; @@ -94,11 +95,15 @@ describe('react => useSSE', () => { }, { timeout: 4000 } ); + + fireEvent.click(screen.getByRole('close-btn')); + await untilCbCalled(setTimeout, 200); + expect(screen.getByRole('status')).toHaveTextContent('closed'); }); // ! 有初始数据,不立即发送请求 test('should get the initial data and NOT send request immediately', async () => { - await prepareAlova(); + const alovaInst = await prepareAlova(); const poster = (data: any) => alovaInst.Get(`/${TriggerEventName}`, data); const initialData = 'initial-data'; const testDataA = 'test-data-1'; @@ -178,7 +183,7 @@ describe('react => useSSE', () => { // ! 有初始数据,立即发送请求 test('should get the initial data and send request immediately', async () => { - await prepareAlova(); + const alovaInst = await prepareAlova(); const poster = (data: any) => alovaInst.Get(`/${TriggerEventName}`, data); const initialData = 'initial-data'; const testDataA = 'test-data-1'; @@ -230,7 +235,7 @@ describe('react => useSSE', () => { // ! 测试关闭后重新连接 test('should not trigger handler after close', async () => { - await prepareAlova(); + const alovaInst = await prepareAlova(); const poster = (data: any) => alovaInst.Get(`/${TriggerEventName}`, data); const testDataA = 'test-data-1'; const testDataB = 'test-data-2'; @@ -327,7 +332,7 @@ describe('react => useSSE', () => { // ! 打开失败应该报错,立即发送请求 test('should throw error then try to connect a not exist url', async () => { - await prepareAlova(); + const alovaInst = await prepareAlova(); const poster = (data: any) => alovaInst.Get('/not-exist-path', data); let recv = undefinedValue; @@ -359,7 +364,7 @@ describe('react => useSSE', () => { render(() as ReactElement); - await untilCbCalled(setTimeout, 500); + await untilCbCalled(setTimeout, 1500); await screen.findByText(/closed/); expect(screen.getByRole('data')).toBeEmptyDOMElement(); @@ -371,7 +376,7 @@ describe('react => useSSE', () => { // ! 打开失败应该报错,不立即发送请求 test('should throw error then try to connect a not exist url (immediate: false)', async () => { - await prepareAlova(); + const alovaInst = await prepareAlova(); const poster = (data: any) => alovaInst.Get('/not-exist-path', data); let recv = undefinedValue; @@ -399,7 +404,7 @@ describe('react => useSSE', () => { {data} @@ -441,7 +446,7 @@ describe('react => useSSE', () => { const mockResponseErrorFn = jest.fn(); const mockResponseCompleteFn = jest.fn(); - alovaInst = getAlovaInstance(ReactHook, { + const alovaInst = getAlovaInstance(ReactHook, { baseURL: `http://localhost:${port}`, responseExpect: data => { mockResponseFn(); @@ -600,7 +605,7 @@ describe('react => useSSE', () => { const mockResponseErrorFn = jest.fn(); const mockResponseCompleteFn = jest.fn(); - alovaInst = getAlovaInstance(ReactHook, { + const alovaInst = getAlovaInstance(ReactHook, { baseURL: `http://localhost:${port}`, responseExpect: () => { mockResponseFn(); diff --git a/packages/scene-vue/test/useSSE.spec.ts b/packages/scene-vue/test/useSSE.spec.ts index 80ab2cc..ec205a8 100644 --- a/packages/scene-vue/test/useSSE.spec.ts +++ b/packages/scene-vue/test/useSSE.spec.ts @@ -1,14 +1,14 @@ +import { usePromise } from '@/helper'; import '@testing-library/jest-dom'; import { fireEvent, render, screen, waitFor } from '@testing-library/vue'; -import { Alova, createAlova } from 'alova'; +import { createAlova } from 'alova'; import GlobalFetch from 'alova/GlobalFetch'; import VueHook from 'alova/vue'; import ES from 'eventsource'; import { AddressInfo } from 'net'; -import { Ref } from 'vue'; import { IntervalEventName, IntervalMessage, TriggerEventName, server, send as serverSend } from '~/test/sseServer'; import { untilCbCalled } from '~/test/utils'; -import { AnyFn, FetchRequestInit, SSEHookReadyState } from '~/typings/general'; +import { AnyFn, SSEHookReadyState } from '~/typings/general'; import { useSSE } from '..'; import { AlovaSSEMessageEvent } from '../typings/general'; import CompUseSSEGlobalResponse from './components/use-sse-global-response.vue'; @@ -16,10 +16,12 @@ import CompUseSSE from './components/use-sse.vue'; Object.defineProperty(global, 'EventSource', { value: ES, writable: false }); -let alovaInst: Alova, Ref, FetchRequestInit, Response, Headers>; - afterEach(() => { - server.close(); + const { promise, resolve } = usePromise(); + if (server.listening) { + server.close(resolve); + return promise; + } }); type AnyMessageType = AlovaSSEMessageEvent; @@ -30,7 +32,7 @@ type AnyMessageType = AlovaSSEMessageEvent { await server.listen(); const { port } = server.address() as AddressInfo; - alovaInst = createAlova({ + return createAlova({ baseURL: `http://127.0.0.1:${port}`, statesHook: VueHook, requestAdapter: GlobalFetch(), @@ -41,9 +43,9 @@ const prepareAlova = async () => { describe('vue => useSSE', () => { // ! 无初始数据,不立即发送请求 test('should default NOT request immediately', async () => { - await prepareAlova(); + const alovaInst = await prepareAlova(); const poster = (data: any) => alovaInst.Get(`/${IntervalEventName}`, data); - const { on, onOpen, data, readyState, send } = useSSE(poster); + const { on, onOpen, data, readyState, send, close } = useSSE(poster); const cb = jest.fn(); const openCb = jest.fn(); on(IntervalEventName, cb); @@ -67,25 +69,26 @@ describe('vue => useSSE', () => { await untilCbCalled(setTimeout, 100); expect(openCb).toHaveBeenCalled(); - const { data: recvData } = (await untilCbCalled(onIntervalCb)) as AnyMessageType; + const { data: recvData } = (await untilCbCalled(onIntervalCb)) as AnyMessageType; expect(readyState.value).toStrictEqual(SSEHookReadyState.OPEN); expect(cb).toHaveBeenCalled(); expect(recvData).toEqual(IntervalMessage); expect(data.value).toStrictEqual(IntervalMessage); + close(); }, 3000); // ! 有初始数据,不立即发送请求 test('should get the initial data and NOT send request immediately', async () => { - await prepareAlova(); + const alovaInst = await prepareAlova(); const poster = (data: any) => alovaInst.Get(`/${TriggerEventName}`, data); const initialData = { id: 9527, name: 'Tom', age: 18 }; - const { onMessage, onOpen, data, readyState, send } = useSSE(poster, { initialData }); + const { onMessage, onOpen, data, readyState, send, close } = useSSE(poster, { initialData }); const testDataA = 'test-data-1'; const testDataB = 'test-data-2'; @@ -117,13 +120,14 @@ describe('vue => useSSE', () => { await send(); serverSend(testDataB); - const { data: recvData } = (await untilCbCalled(onMessage)) as AnyMessageType; + const { data: recvData } = (await untilCbCalled(onMessage)) as AnyMessageType; expect(readyState.value).toStrictEqual(SSEHookReadyState.OPEN); expect(cb).toHaveBeenCalled(); expect(recvData).toEqual(testDataB); expect(data.value).toStrictEqual(testDataB); + close(); }); // ! 有初始数据,立即发送请求 @@ -145,6 +149,7 @@ describe('vue => useSSE', () => { expect(screen.getByRole('data')).toHaveTextContent(initialData); await screen.findByText(/opened/); + await untilCbCalled(setTimeout, 100); expect(screen.getByRole('onopen').innerHTML).toStrictEqual('1'); @@ -291,6 +296,7 @@ describe('vue => useSSE', () => { expect(screen.getByRole('data')).toHaveTextContent(initialData); await screen.findByText(/opened/); + await untilCbCalled(setTimeout, 100); expect(screen.getByRole('onopen').innerHTML).toStrictEqual('1'); expect(screen.getByRole('on-response').innerHTML).toStrictEqual('0'); @@ -375,6 +381,7 @@ describe('vue => useSSE', () => { expect(screen.getByRole('data')).toHaveTextContent(initialData); await screen.findByText(/opened/); + await untilCbCalled(setTimeout, 100); expect(screen.getByRole('onopen').innerHTML).toStrictEqual('1'); expect(screen.getByRole('on-response').innerHTML).toStrictEqual('0'); diff --git a/src/hooks/useSSE.ts b/src/hooks/useSSE.ts index 6938801..2bf1bd4 100644 --- a/src/hooks/useSSE.ts +++ b/src/hooks/useSSE.ts @@ -164,6 +164,7 @@ export default ( */ const createSSEEvent = async (eventFrom: keyof EventSourceEventMap, dataOrError: Promise) => { assert(!!eventSource.current, 'EventSource is not initialized'); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const es = eventSource.current!; const ev = (type: AlovaHookEventType, data?: any, error?: Error) => { @@ -362,7 +363,7 @@ export default ( }); }); - return promiseObj!.promise; + return promiseObj.promise; }); onUnmounted$(() => {