admin管理员组

文章数量:1129450

I have an SSE connection setup for keeping track of a payment process, where incoming POST requests trigger data to be sent over the stream:

// payment/stream/+server.ts
export const GET = async ({ request }) => {
  const headers = new Headers({
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive',
    'Access-Control-Allow-Origin': '*'
  });

  const body = new ReadableStream({
    start(controller) {
      // Send an initial "ping" event
      
      controller.enqueue('event: ping\ndata: connected\n\n');

      request.signal.addEventListener('abort', () => {
        console.log("Client disconnected");
        controller.close();
        controller = undefined;
      })

      sendStatus = (status: string) => {
        if (controller) {
          controller.enqueue(`event: payment-status\ndata: ${JSON.stringify({ status })}\n\n`);
        } else {
          console.error("No active SSE connection");
          throw new Error("No active SSE connection");
        }
      }
    }
  })

  

  return new Response(body, { headers });
}

export async function POST({ request }) {
  const new_status = (await request.json()).status;


  try {
    sendStatus(new_status);
  } catch (error) {
    return new Response(JSON.stringify({ error: 'Error sending payment status' }), { status: 500 });
  }
  return new Response(JSON.stringify({ success: true }), { status: 200 });
}

On my Sveltekit frontend, I have setup EventListeners to catch the incoming data:

let connection;
function startSSEConnection() {
    if (connection) {
        connection.close();
        connection = null;
    }

    connection = new EventSource('/payment/stream');

    connection.onopen = () => {
        console.log('SSE connection opened');
        payment_status = '';
    };

    connection.onerror = (e) => {
        console.error('error with sse: ', e);
    };

    connection.addEventListener('ping', (e) => {
        if (e.data == 'connected') {
            axios
                .post('/payment/initialize', {
                    amount: calcTotalPrice().toFixed(2)
                })
                .then((response) => {
                    if (response.status !== 200) {
                        title = 'Payment cannot be processed at the moment.';
                        subtitle = 'Please try again later.';

                        cancelOrder();
                    }
                });
        }
    });

    connection.addEventListener('payment-status', (e) => {
        payment_status = JSON.parse(e.data).status;
    });
}

I want to know how to write unit tests for both the backend and frontend side of this.

For testing the backend, I am thinking of just creating an EventSource object and seeing if events are fired on it. However, it seems i'll have to mock EventSource entirely? I'm lost.

For testing the frontend, I am thinking of mocking the EventSource object and sending fake events to it. However, I cannot seem to properly mock it (I am new to mocking).

If anyone has had to unit test an SSE, how did you do it? Is there a better way to setup my SSE that is more testable?

I tried mocking the EventSource like this:

global.EventSource = vi.fn(() => ({
    addEventListener: vi.fn(),
    removeEventListener: vi.fn(),
    close: vi.fn(),
    onerror: null,
    onopen: null
}));

however when i try to get the 'connection' object that is created from the constructor, i get undefined:

connection = global.EventSource.mock.results[0]?.value;

PLEASE let me know if you need more information/context on what I have tried.

本文标签: javascriptHow to mock an sse connection for unit testingStack Overflow