The Talent500 Blog

SafeTest: A Novel Approach to Front-End Testing

SafeTest is an innovative library that presents a fresh perspective on end-to-end (E2E) testing specifically for web-based user interface (UI) applications. This article explores the challenges associated with traditional UI testing and how SafeTest aims to overcome them.

The Challenges of Traditional UI Testing

UI testing has traditionally relied on unit testing or integration testing methods. Each approach comes with its own set of trade-offs, forcing developers to choose between controlling the test fixture and setup or managing the test driver.

In response to these challenges, solutions like E2E Component Testing have emerged from tools like Cypress and Playwright. However, these tools still face limitations due to their architecture, particularly when dealing with complex enterprise applications that may involve OAuth or intricate build pipelines.

Welcome to SafeTest

SafeTest addresses these traditional UI testing challenges through a novel approach. The core concept involves injecting hooks during the application bootstrapping stage that enable tests to run seamlessly. This method ensures no measurable impact on regular app usage since SafeTest employs lazy loading to dynamically load tests only when needed. Once integrated, developers can utilize Playwright to execute regular tests while maintaining optimal browser control.

This innovative approach unlocks several exciting features:

Test Examples with SafeTest

SafeTest is designed for familiarity, allowing users accustomed to UI testing frameworks to feel at home. Below are examples demonstrating how to test an entire application and specific components using SafeTest:

import { describe, it, expect } from 'safetest/jest';
import { render } from 'safetest/react';

describe('my app', () => {
it('loads the main page', async () => {
const { page } = await render();
await expect(page.getByText('Welcome to the app')).toBeVisible();
expect(await page.screenshot()).toMatchImageSnapshot();
});
});

Testing a specific component is equally straightforward:

import { describe, it, expect, browserMock } from 'safetest/jest';
import { render } from 'safetest/react';

describe('Header component', () => {
it('has a normal mode', async () => {
const { page } = await render(<Header />);
await expect(page.getByText('Admin')).not.toBeVisible();
});

it('has an admin mode', async () => {
const { page } = await render(<Header admin={true} />);
await expect(page.getByText('Admin')).toBeVisible();
});

it('calls the logout handler when signing out', async () => {
const spy = browserMock.fn();
const { page } = await render(<Header handleLogout={spy} />);
await page.getByText('logout').click();
expect(await spy).toHaveBeenCalledWith();
});
});

SafeTest utilizes React Context for value overrides during tests. This feature allows developers to modify components easily for testing purposes. For example:

import { useAsync } from 'react-use';
import { fetchPerson } from './api/person';

export const People: React.FC = () => {
const { data: people, loading, error } = useAsync(fetchPeople);

if (loading) return <Loader />;
if (error) return <ErrorPage error={error} />;
return <Table data={data} rows={...} />;
}

By introducing an override:

import { fetchPerson } from './api/person';
import { createOverride } from 'safetest/react';

const FetchPerson = createOverride(fetchPerson);

export const People: React.FC = () => {
const fetchPeople = FetchPerson.useValue();

const { data: people, loading, error } = useAsync(fetchPeople);

if (loading) return <Loader />;
if (error) return <ErrorPage error={error} />;
return <Table data={data} rows={...} />;
}

Reporting Capabilities

SafeTest includes robust reporting features that automatically link video replays and provide access to Playwright’s trace viewer. Users can deep link directly to tested components for enhanced analysis.

SafeTest in Corporate Environments

Many corporations require authentication for their applications. This often complicates local testing environments. SafeTest can be adapted by creating wrappers that facilitate automatic user generation and authentication management.

For example:

While this article highlights SafeTest’s compatibility with React applications, it is not limited to this framework. SafeTest also supports Vue, Svelte, Angular, Next.js, and Gatsby. It operates using either Jest or Vitest based on your project setup.

Conclusion

SafeTest stands out as a powerful testing framework gaining traction in organizations like Netflix. It simplifies test authoring while providing detailed reports on failures complete with playback links. As it continues to evolve, SafeTest promises significant advancements in UI testing methodologies. Feedback and contributions are welcomed as it seeks to revolutionize front-end testing practices.

Read more such articles from our Newsletter here.

0