Skip to content

Commit e6c9210

Browse files
test: add integration tests for React 17, 18, and 19
- Unit tests with vitest for each React version - Sample app with Vite + Playwright e2e tests for each version - React 17 uses ReactDOM.render, React 18/19 use createRoot
1 parent a550bd7 commit e6c9210

33 files changed

+694
-1
lines changed

.npmignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
**/tsconfig.webpack.json
66
**/node_modules
77
downstream_projects
8+
integration
89
logo
910
src
1011
scripts

downstream_projects.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
{
2-
"sample-app-react": "https://github.com/ui-router/sample-app-react.git"
2+
"sample-app-react": "https://github.com/ui-router/sample-app-react.git",
3+
"react-versions": {
4+
"react17": "./integration/react17",
5+
"react18": "./integration/react18",
6+
"react19": "./integration/react19"
7+
}
38
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/**
2+
* Sanity test for @uirouter/react with React 17
3+
* This test verifies basic functionality works with React 17
4+
*/
5+
import { describe, it, expect } from 'vitest';
6+
import * as React from 'react';
7+
import { render, screen, waitFor } from '@testing-library/react';
8+
import { UIRouter, UIView, UISref, pushStateLocationPlugin } from '@uirouter/react';
9+
import { memoryLocationPlugin } from '@uirouter/core';
10+
11+
const Home = () => <div data-testid="home">Home Page</div>;
12+
const About = () => <div data-testid="about">About Page</div>;
13+
14+
const states = [
15+
{ name: 'home', url: '/home', component: Home },
16+
{ name: 'about', url: '/about', component: About },
17+
];
18+
19+
describe('@uirouter/react with React 17', () => {
20+
it('renders UIRouter and UIView', async () => {
21+
render(
22+
<UIRouter plugins={[memoryLocationPlugin]} states={states}>
23+
<UIView />
24+
</UIRouter>
25+
);
26+
27+
// Should render without crashing
28+
expect(document.body).toBeDefined();
29+
});
30+
31+
it('navigates to a state and renders the component', async () => {
32+
const { container } = render(
33+
<UIRouter plugins={[memoryLocationPlugin]} states={states}>
34+
<div>
35+
<nav>
36+
<UISref to="home">
37+
<a data-testid="home-link">Home</a>
38+
</UISref>
39+
<UISref to="about">
40+
<a data-testid="about-link">About</a>
41+
</UISref>
42+
</nav>
43+
<UIView />
44+
</div>
45+
</UIRouter>
46+
);
47+
48+
// Click home link
49+
screen.getByTestId('home-link').click();
50+
51+
await waitFor(() => {
52+
expect(screen.getByTestId('home')).toBeDefined();
53+
});
54+
});
55+
56+
it('UISref generates correct href', async () => {
57+
render(
58+
<UIRouter plugins={[memoryLocationPlugin]} states={states}>
59+
<UISref to="about">
60+
<a data-testid="link">About</a>
61+
</UISref>
62+
</UIRouter>
63+
);
64+
65+
await waitFor(() => {
66+
const link = screen.getByTestId('link');
67+
expect(link.getAttribute('href')).toContain('/about');
68+
});
69+
});
70+
});
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { test, expect } from '@playwright/test';
2+
3+
test.describe('UI-Router React 17 Sample App', () => {
4+
test('loads and navigates between states', async ({ page }) => {
5+
await page.goto('/');
6+
7+
// Should have navigation links
8+
await expect(page.getByTestId('home-link')).toBeVisible();
9+
await expect(page.getByTestId('about-link')).toBeVisible();
10+
11+
// Navigate to home
12+
await page.getByTestId('home-link').click();
13+
await expect(page.getByTestId('home-title')).toHaveText('Home Page');
14+
15+
// Navigate to about
16+
await page.getByTestId('about-link').click();
17+
await expect(page.getByTestId('about-title')).toHaveText('About Page');
18+
19+
// Navigate back to home
20+
await page.getByTestId('home-link').click();
21+
await expect(page.getByTestId('home-title')).toHaveText('Home Page');
22+
});
23+
});

integration/react17/index.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>UI-Router React 17 Sample App</title>
7+
</head>
8+
<body>
9+
<div id="root"></div>
10+
<script type="module" src="/src/main.tsx"></script>
11+
</body>
12+
</html>

integration/react17/package.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "integration-test-react17",
3+
"version": "1.0.0",
4+
"private": true,
5+
"description": "Integration tests for @uirouter/react with React 17",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "vite build",
9+
"preview": "vite preview",
10+
"test": "vitest run && npm run build && npx playwright install chromium && npx playwright test"
11+
},
12+
"dependencies": {
13+
"react": "^17.0.2",
14+
"react-dom": "^17.0.2"
15+
},
16+
"devDependencies": {
17+
"@playwright/test": "^1.49.1",
18+
"@testing-library/react": "^12.1.5",
19+
"@types/react": "^17.0.80",
20+
"@types/react-dom": "^17.0.25",
21+
"@vitejs/plugin-react": "^4.3.4",
22+
"jsdom": "^27.4.0",
23+
"typescript": "^5.9.3",
24+
"vite": "^6.0.7",
25+
"vitest": "^4.0.16"
26+
}
27+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { defineConfig } from '@playwright/test';
2+
3+
export default defineConfig({
4+
testDir: './e2e',
5+
timeout: 30000,
6+
use: {
7+
baseURL: 'http://localhost:4173',
8+
},
9+
webServer: {
10+
command: 'npm run preview',
11+
port: 4173,
12+
reuseExistingServer: !process.env.CI,
13+
},
14+
});

integration/react17/src/App.tsx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import React from 'react';
2+
import { UIRouter, UIView, UISref, hashLocationPlugin } from '@uirouter/react';
3+
4+
const Home = () => (
5+
<div>
6+
<h1 data-testid="home-title">Home Page</h1>
7+
<p>Welcome to the UI-Router React 17 sample app!</p>
8+
</div>
9+
);
10+
11+
const About = () => (
12+
<div>
13+
<h1 data-testid="about-title">About Page</h1>
14+
<p>This is a simple sample application.</p>
15+
</div>
16+
);
17+
18+
const states = [
19+
{ name: 'home', url: '/home', component: Home },
20+
{ name: 'about', url: '/about', component: About },
21+
];
22+
23+
const App = () => (
24+
<UIRouter plugins={[hashLocationPlugin]} states={states}>
25+
<div>
26+
<nav>
27+
<UISref to="home">
28+
<a data-testid="home-link">Home</a>
29+
</UISref>
30+
{' | '}
31+
<UISref to="about">
32+
<a data-testid="about-link">About</a>
33+
</UISref>
34+
</nav>
35+
<hr />
36+
<UIView />
37+
</div>
38+
</UIRouter>
39+
);
40+
41+
export default App;

integration/react17/src/main.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import React from 'react';
2+
import ReactDOM from 'react-dom';
3+
import App from './App';
4+
5+
ReactDOM.render(
6+
<React.StrictMode>
7+
<App />
8+
</React.StrictMode>,
9+
document.getElementById('root')
10+
);

integration/react17/tsconfig.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES2020",
4+
"useDefineForClassFields": true,
5+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
6+
"module": "ESNext",
7+
"skipLibCheck": true,
8+
"moduleResolution": "bundler",
9+
"allowImportingTsExtensions": true,
10+
"resolveJsonModule": true,
11+
"isolatedModules": true,
12+
"noEmit": true,
13+
"jsx": "react-jsx",
14+
"strict": true,
15+
"esModuleInterop": true
16+
},
17+
"include": ["src", "e2e", "__tests__"]
18+
}

0 commit comments

Comments
 (0)