Skip to content

Commit 9aab744

Browse files
Add vite dev server tests
1 parent d0dfbde commit 9aab744

File tree

9 files changed

+1081
-481
lines changed

9 files changed

+1081
-481
lines changed

.github/workflows/test-isolated.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ jobs:
5252
- name: Install
5353
run: pnpm install
5454

55+
- name: Configure Playwright
56+
run: |
57+
pnpm exec playwright install-deps
58+
pnpm exec playwright install
59+
5560
- name: Build Packages
5661
run: pnpm build:packages
5762

pnpm-lock.yaml

Lines changed: 786 additions & 481 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Vite Dev Server Test
2+
3+
This tool is designed to catch any issues with our package's compatibility with Vite configurations. It runs end-to-end tests that verify PowerSync works correctly when served through a Vite dev server.
4+
5+
## Purpose
6+
7+
This test suite ensures that:
8+
9+
- Our package (`@powersync/web`) is compatible with Vite's build system
10+
- Vite plugins (WASM, top-level await) work correctly with our code
11+
- The application functions properly when served through Vite's dev server
12+
- Web workers and WASM files are loaded correctly in a Vite environment
13+
14+
## How It Works
15+
16+
The test suite:
17+
18+
1. Starts a Vite dev server programmatically using the same configuration as our example-vite demo
19+
2. Launches a Playwright browser instance
20+
3. Navigates to the dev server
21+
4. Verifies that the application loads and functions correctly (e.g., displays customer data)
22+
23+
## Running the Tests
24+
25+
```bash
26+
# Install dependencies (if not already done)
27+
pnpm install
28+
29+
# Run tests
30+
pnpm test
31+
```
32+
33+
## Test Structure
34+
35+
- **`src/`** - Contains the application code (similar to `demos/example-vite`)
36+
- `index.html` - HTML structure
37+
- `index.js` - Application logic that uses PowerSync
38+
- **`tests/`** - Contains the E2E test
39+
- `dev-server.test.ts` - Node.js E2E test that starts the dev server and verifies it works
40+
- **`vite.config.ts`** - Vite configuration for building/serving the app
41+
- **`vitest.config.ts`** - Vitest configuration for running Node.js E2E tests
42+
43+
## Notes
44+
45+
- The tests run in **Node.js environment** (not browser mode) to allow programmatic server control
46+
- Playwright is used to interact with the browser and verify the application behavior
47+
- The test ensures the same Vite configuration used in our demos works correctly
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"name": "vite-dev-server-test",
3+
"version": "0.0.0",
4+
"private": true,
5+
"type": "module",
6+
"scripts": {
7+
"test": "vitest run"
8+
},
9+
"dependencies": {
10+
"@powersync/web": "workspace:*"
11+
},
12+
"devDependencies": {
13+
"@vitest/browser": "^3.2.4",
14+
"playwright": "^1.51.0",
15+
"vite": "^5.0.12",
16+
"vite-plugin-top-level-await": "^1.4.1",
17+
"vite-plugin-wasm": "^3.3.0",
18+
"vitest": "^3.2.4"
19+
}
20+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!doctype html>
2+
<html>
3+
4+
<head>
5+
<script type="module" src="./index.js"></script>
6+
</head>
7+
8+
<body>
9+
<h1>Vite bundling test: Check the console to see it in action!</h1>
10+
<h2>Customers:</h2>
11+
<ul id="customers-list"></ul>
12+
</body>
13+
14+
</html>
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { PowerSyncDatabase, Schema, Table, column, createBaseLogger } from '@powersync/web';
2+
3+
createBaseLogger().useDefaults();
4+
5+
/**
6+
* A placeholder connector which doesn't do anything.
7+
* This is just used to verify that the sync workers can be loaded
8+
* when connecting.
9+
*/
10+
class DummyConnector {
11+
async fetchCredentials() {
12+
return {
13+
endpoint: '',
14+
token: ''
15+
};
16+
}
17+
18+
async uploadData(database) {}
19+
}
20+
21+
const customers = new Table({ name: column.text });
22+
23+
export const AppSchema = new Schema({ customers });
24+
25+
let PowerSync;
26+
27+
const openDatabase = async () => {
28+
PowerSync = new PowerSyncDatabase({
29+
schema: AppSchema,
30+
database: { dbFilename: 'test.sqlite' }
31+
});
32+
33+
await PowerSync.init();
34+
35+
// Run local statements.
36+
await PowerSync.execute('INSERT INTO customers(id, name) VALUES(uuid(), ?)', ['Fred']);
37+
38+
const result = await PowerSync.getAll('SELECT * FROM customers');
39+
console.log('contents of customers: ', result);
40+
41+
// Display customers in the HTML list
42+
const customersList = document.getElementById('customers-list');
43+
if (customersList) {
44+
// Clear existing list items
45+
customersList.textContent = '';
46+
// Create and append list items
47+
result.forEach((customer) => {
48+
const listItem = document.createElement('li');
49+
listItem.textContent = customer.name || 'Unknown';
50+
customersList.appendChild(listItem);
51+
});
52+
}
53+
54+
console.log(
55+
`Attempting to connect in order to verify web workers are correctly loaded.
56+
This doesn't use any actual network credentials.
57+
Network errors will be shown: these can be ignored.`
58+
);
59+
60+
/**
61+
* Try and connect, this will setup shared sync workers
62+
* This will fail due to not having a valid endpoint,
63+
* but it will try - which is all that matters.
64+
*/
65+
await PowerSync.connect(new DummyConnector());
66+
};
67+
68+
document.addEventListener('DOMContentLoaded', (event) => {
69+
openDatabase();
70+
});
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/**
2+
* Node.js E2E test for Vite dev server.
3+
* This test runs in Node.js environment (not browser mode) to:
4+
* 1. Start a Vite dev server programmatically
5+
* 2. Launch a Playwright browser
6+
* 3. Navigate to the dev server and verify the application works correctly
7+
*
8+
* This ensures our package is compatible with Vite configurations and works
9+
* correctly when served through a Vite dev server.
10+
*/
11+
import { dirname, resolve } from 'path';
12+
import { chromium } from 'playwright';
13+
import { fileURLToPath } from 'url';
14+
import { createServer } from 'vite';
15+
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
16+
17+
const __filename = fileURLToPath(import.meta.url);
18+
const __dirname = dirname(__filename);
19+
const projectRoot = resolve(__dirname, '..');
20+
21+
describe('Vite Dev Server E2E', () => {
22+
let server;
23+
let browser;
24+
let page;
25+
let serverUrl;
26+
27+
beforeAll(async () => {
28+
// Start Vite dev server using the config file
29+
server = await createServer({
30+
mode: 'development',
31+
configFile: resolve(projectRoot, 'vite.config.ts'),
32+
server: {
33+
port: 0 // Use random available port
34+
}
35+
});
36+
await server.listen();
37+
serverUrl = `http://localhost:${server.config.server.port}`;
38+
39+
// Launch browser
40+
browser = await chromium.launch({ headless: true });
41+
page = await browser.newPage();
42+
});
43+
44+
afterAll(async () => {
45+
// Clean up
46+
if (page) await page.close();
47+
if (browser) await browser.close();
48+
if (server) await server.close();
49+
});
50+
51+
it('should display the inserted customer "Fred" in the HTML list when running in dev mode', async () => {
52+
// Navigate to the dev server
53+
await page.goto(serverUrl);
54+
55+
// Wait for the customer list to appear and contain "Fred"
56+
await page.waitForSelector('#customers-list', { timeout: 10000 });
57+
58+
// Wait for "Fred" to appear in the list
59+
await page.waitForFunction(
60+
() => {
61+
const customersList = document.getElementById('customers-list');
62+
if (!customersList) return false;
63+
const listItems = customersList.querySelectorAll('li');
64+
const customerNames = Array.from(listItems).map((li) => li.textContent);
65+
return customerNames.includes('Fred');
66+
},
67+
{ timeout: 10000 }
68+
);
69+
70+
// Get all list items and verify
71+
const listItems = await page.locator('#customers-list li').all();
72+
const customerNames = await Promise.all(listItems.map((li) => li.textContent()));
73+
74+
// Verify "Fred" is in the list
75+
expect(customerNames).toContain('Fred');
76+
});
77+
});
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* Vite configuration for the test application.
3+
* This config is used by the Node.js E2E test to start a dev server and verify
4+
* our package's compatibility with Vite configurations.
5+
*/
6+
import { defineConfig } from 'vite';
7+
import topLevelAwait from 'vite-plugin-top-level-await';
8+
import wasm from 'vite-plugin-wasm';
9+
10+
// https://vitejs.dev/config/
11+
export default defineConfig({
12+
root: 'src',
13+
build: {
14+
outDir: '../dist',
15+
rollupOptions: {
16+
input: 'src/index.html'
17+
},
18+
emptyOutDir: true
19+
},
20+
envDir: '..',
21+
optimizeDeps: {
22+
// Don't optimize these packages as they contain web workers and WASM files.
23+
exclude: ['@journeyapps/wa-sqlite', '@powersync/web']
24+
},
25+
plugins: [wasm(), topLevelAwait()],
26+
worker: {
27+
format: 'es',
28+
plugins: () => [wasm(), topLevelAwait()]
29+
}
30+
});
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* Vitest configuration for Node.js E2E tests.
3+
* These tests run in Node.js environment (not browser mode) to allow starting
4+
* a Vite dev server programmatically and testing it with Playwright.
5+
*/
6+
import topLevelAwait from 'vite-plugin-top-level-await';
7+
import wasm from 'vite-plugin-wasm';
8+
import { defineConfig } from 'vitest/config';
9+
10+
export default defineConfig({
11+
root: 'src',
12+
server: {
13+
headers: {
14+
'Cross-Origin-Opener-Policy': 'same-origin',
15+
'Cross-Origin-Embedder-Policy': 'require-corp'
16+
}
17+
},
18+
envDir: '..',
19+
optimizeDeps: {
20+
exclude: ['@journeyapps/wa-sqlite', '@powersync/web']
21+
},
22+
plugins: [wasm(), topLevelAwait()],
23+
worker: {
24+
format: 'es',
25+
plugins: () => [wasm(), topLevelAwait()]
26+
},
27+
test: {
28+
globals: true,
29+
include: ['../tests/**/*.test.ts'],
30+
maxConcurrency: 1
31+
}
32+
});

0 commit comments

Comments
 (0)