Attention

This is the documentation for HARP Proxy, actually published as an early preview. Both the software and documentation are a work in progress, and although we already use it on various production servers, they may contain inaccuracies, typographical errors, huge mistakes and empty pages. We work hard to eradicate all mistakes and implement stuff, but it is a long and tedious process. We appreciate your patience and understanding. Of course, any help will be greatly appreciated.

End-to-End Tests

The Dashboard Application uses Playwright for end-to-end testing.

Playwright is a Node.js library for automating browser tasks. In our project, we use Playwright for end-to-end (E2E) testing. E2E tests simulate real user scenarios by running tests in a real browser environment.

Here’s an example of a basic Playwright test:

import { test, expect } from '@playwright/test';

test('Example test', async ({ page }) => {
  await page.goto('https://example.com');
  const title = await page.title();
  expect(title).toBe('Example Domain');
});

To run our E2E tests, we use the command pnpm run test:browser. This command starts Playwright, which opens a new browser window and runs our E2E tests.

Running E2E Tests

To run all tests, use the following command in the dashboard application directory:

pnpm test

This will also include the unit tests. If you only want to run the browser tests, use the following command:

pnpm test:browser

We can also run a single test file by specifying the file path as an argument to the test command:

pnpm run test:browser transactions.spec.ts

Writing E2E Tests

We use Playwright for end-to-end testing to simulate real user interactions with our application.

Playwright provides a high-level API to control headless or non-headless browsers, enabling us to automate browser tasks and test our application in real-world scenarios.

import { test, expect, request } from "@playwright/test"

test.beforeEach(async ({ page }) => {
  await page.goto("/transactions")
  await page.waitForFunction(() => document.body.innerText.includes("Endpoint"))
})

test.describe("Transactions Page", () => {
  test("Interacting with the filter side bar", async ({ page }) => {
    const requestMethodButton = await page.$('span:has-text("Request Method")')
    const getLabel = await page.getByLabel("GET")
    expect(getLabel).toBeVisible()

    await requestMethodButton?.click()
    expect(getLabel).not.toBeVisible()

    const endpointButton = await page.getByText("Endpoint", { exact: true })
    const endpoint1Label = await page.getByLabel("endpoint1")
    expect(endpoint1Label).toBeVisible()

    await endpointButton?.click()
    expect(endpoint1Label).not.toBeVisible()
  })
})

In this example, we use Playwright to test the interactions with the filter sidebar on the Transactions page. We navigate to the Transactions page before each test and wait for the page to load. In the test, we simulate user interactions with the filter sidebar, such as clicking on buttons and checking the visibility of elements. We use Playwright’s expect function to assert the expected outcomes of these interactions.

This approach allows us to ensure that our application behaves as expected when users interact with it, providing us with confidence in the quality of our application.

Overriding API Mocks

In some cases, we might want to override the default handlers for a single test. We can do this by accessing the worker object on the window object and calling its use method with a new handler.

test("Override msw worker for system dependencies", async ({ page }) => {
  // Test setup code here...

  await page.evaluate(() => {
    const { worker, http, HttpResponse } = window.msw
    worker.use(
      http.get("/api/system/dependencies", function override() {
        return HttpResponse.json({ python: ["pydantic", "tensorflow"] })
      }),
    )
  })

  // Test code here...
})

In this test, we override the handler for GET requests to /api/system/dependencies to return a predefined JSON response. This allows us to control the data that our application receives from the API in this specific test.

Implementation details

In our project, we set up the Mock Service Worker (MSW) in development mode to mock API responses. This is done in the main.tsx file, where we conditionally import the MSW worker and start it if the application is running in development mode.

// Enable mocking in development using msw server set up for the browser
async function enableMocking() {
  if (process.env.NODE_ENV !== "development") {
    return
  }

  const { worker, http, HttpResponse } = await import("./tests/mocks/browser")

  // @ts-ignore
  // Propagate the worker and `http` references to be globally available.
  // This would allow to modify request handlers on runtime.
  window.msw = {
    worker,
    http,
    HttpResponse,
  }
  return worker.start()
}

In this function, we first check if the application is running in development mode. If it is, we dynamically import the MSW worker, http, and HttpResponse from our browser mocks. We then assign these to the window.msw object, making them globally available. This allows us to modify the request handlers at runtime, which is useful for overriding handlers in specific tests. Finally, we start the MSW worker, which begins intercepting network requests according to the predefined handlers.