Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 3 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -213,20 +213,12 @@ jobs:
with:
name: sqlpage-linux-debug
path: ${{ runner.temp }}/sqlpage-bin
- name: Start official site and wait for it to be ready
timeout-minutes: 1
- name: Run Playwright tests
run: |
chmod +x "${{ runner.temp }}/sqlpage-bin/sqlpage"
"${{ runner.temp }}/sqlpage-bin/sqlpage" 2>/tmp/stderrlog &
tail -f /tmp/stderrlog | grep -q "started successfully"
working-directory: ./examples/official-site
- name: Run Playwright tests
run: npx playwright test
- name: show server logs
if: failure()
run: cat /tmp/stderrlog
SQLPAGE_BINARY="${{ runner.temp }}/sqlpage-bin/sqlpage" npx playwright test
- uses: actions/upload-artifact@v7
if: always()
if: ${{ !cancelled() }}
with:
name: playwright-report
path: ./tests/end-to-end/playwright-report/
Expand Down
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ DATABASE_URL='mssql://root:Password123!@localhost/sqlpage' cargo test

ODBC tests require the database-specific ODBC driver on the host; starting the container is not sufficient. See the PostgreSQL ODBC and Oracle matrix entries in [CI](./.github/workflows/ci.yml) for driver setup and connection strings. On Linux and macOS, `cargo test --features odbc-static` matches CI's static unixODBC linking.

For dynamic frontend changes, run the Playwright tests under `tests/end-to-end/` as described in [CONTRIBUTING.md](./CONTRIBUTING.md). For examples containing `test.hurl`, run `scripts/test-examples-hurl.sh <example-path>`.
For dynamic frontend changes, run the Playwright tests under `tests/end-to-end/` as described in [CONTRIBUTING.md](./CONTRIBUTING.md). Component browser tests belong in `tests/end-to-end/fixtures/<suite>/{index.sql,test.ts}` and must import the shared `fixture.ts` harness. Exercise components through SQL fixtures and normal page initialization; do not inject synthetic component DOM or call private initialization functions. Prefer Playwright locators and web-first assertions. For examples containing `test.hurl`, run `scripts/test-examples-hurl.sh <example-path>`.

### Documentation

Expand All @@ -143,5 +143,6 @@ official documentation website sql tables:
- SQLPage functions: one `async fn` module under `src/webserver/database/sqlpage_functions/functions/`, declared with `mod` and registered with `sqlpage_functions!` in `functions.rs`. See its [README](./src/webserver/database/sqlpage_functions/README.md).
- [Configuration](./configuration.md): see [AppConfig](./src/app_config.rs)
- Routing: file-based in `src/webserver/routing.rs`. Missing paths use the nearest ancestor `404.sql`; without one, HTML uses `src/default_404.sql` and other formats receive a plain-text 404.
- Playwright component suites: `tests/end-to-end/fixtures/<suite>/{index.sql,test.ts}` using `tests/end-to-end/fixture.ts`; official-site smoke tests remain in `tests/end-to-end/*.spec.ts`.
- Follow patterns from similar modules before introducing new abstractions.
- frontend: see [css](./sqlpage/sqlpage.css) and [js](./sqlpage/sqlpage.js)
14 changes: 14 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,17 @@ cargo test
We use Playwright for end-to-end testing of dynamic frontend features.
Tests are located in [`tests/end-to-end/`](./tests/end-to-end/). Key areas covered include:

Component tests use deterministic SQL applications under `tests/end-to-end/fixtures/<suite>/`.
Each suite contains an `index.sql` page and a `test.ts` file. Import `test` and `expect` from
`../../fixture`; the shared fixture opens the matching SQL page before every test and waits for
all SQLPage components to initialize. Prefer role, label, and text locators over CSS selectors
when the assertion does not specifically concern generated markup.

Keep official-site smoke and integration tests in root-level `*.spec.ts` files. Component behavior
tests should render real components through their SQL fixture; do not inject component markup or
invoke SQLPage's JavaScript initialization functions directly. Parameterized fixtures may accept
request variables when several tests need the same component with different data.

#### Start a sqlpage instance pointed to the official site source code

```bash
Expand All @@ -118,6 +129,9 @@ npx playwright install chromium
npm run test
```

Playwright starts the component fixture server on port 8081 automatically. The official-site
server on port 8080 must still be started separately as shown above.

## Documentation

### Component Documentation
Expand Down
4 changes: 4 additions & 0 deletions tests/end-to-end/fixture-server/sqlpage.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"database_url": "sqlite::memory:",
"port": 8081
}
34 changes: 34 additions & 0 deletions tests/end-to-end/fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import path from "node:path";
import { test as base, expect } from "@playwright/test";

const fixturesDirectory = path.resolve(__dirname, "fixtures");

export const test = base.extend({
page: async ({ page }, use, testInfo) => {
const fixture = path
.relative(fixturesDirectory, path.dirname(testInfo.file))
.split(path.sep)
.join("/");
const errors: string[] = [];
page.on("pageerror", (error) => errors.push(error.message));

const response = await page.goto(`/${fixture}/`);
expect(response).not.toBeNull();
expect(response?.ok(), `loading ${response?.url()}`).toBe(true);
await expect(
page.getByRole("heading", { name: "An error occurred" }),
"SQL fixture rendered without errors",
).toHaveCount(0);
await expect(
page.locator("[data-pre-init]"),
"component initialization",
).toHaveCount(0);

await use(page);

expect(errors, "uncaught browser errors").toEqual([]);
},
});

export type { Page } from "@playwright/test";
export { expect };
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/area-categories.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'area' AS type, 4 AS marker;
WITH points(series, x, y) AS (VALUES ('A', 'Q1', 1), ('A', 'Q2', 2), ('A', 'Q3', 3), ('B', 'Q2', 20), ('B', 'Q3', 30)) SELECT * FROM points;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/bubble-categories.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'bubble' AS type, 4 AS marker;
WITH points(series, x, y, z) AS (VALUES ('A', 'Q1', 1, 30), ('A', 'Q2', 2, 30), ('B', 'Q2', 5, 70)) SELECT * FROM points;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/chart-and-row-colors.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'bar' AS type, 'azure' AS color, 4 AS marker;
WITH points(series, x, y, color) AS (VALUES ('A', 'Q1', 1, NULL), ('A', 'Q2', 2, 'red')) SELECT * FROM points;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/colored-area.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'area' AS type, 4 AS marker;
WITH points(series, x, y, color) AS (VALUES ('A', 'Q1', 1, 'red'), ('A', 'Q2', 2, 'green')) SELECT * FROM points;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/colored-bar.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'bar' AS type, 4 AS marker;
WITH points(series, x, y, color) AS (VALUES ('A', 'Q1', 1, 'red'), ('A', 'Q2', 2, 'green')) SELECT * FROM points;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/colored-bubble.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'bubble' AS type, 4 AS marker;
WITH points(series, x, y, color, z) AS (VALUES ('A', 'Q1', 1, 'red', 30), ('A', 'Q2', 2, 'green', 30)) SELECT * FROM points;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/colored-column.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'column' AS type, 4 AS marker;
WITH points(series, x, y, color) AS (VALUES ('A', 'Q1', 1, 'red'), ('A', 'Q2', 2, 'green')) SELECT * FROM points;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/colored-heatmap.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'heatmap' AS type, 4 AS marker;
WITH points(series, x, y, color) AS (VALUES ('A', 'Q1', 1, 'red'), ('A', 'Q2', 2, 'green')) SELECT * FROM points;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/colored-horizontal-bar.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'bar' AS type, TRUE AS horizontal, 4 AS marker;
WITH points(series, x, y, color) AS (VALUES ('Accounts', '30 days', 100, 'red'), ('Accounts', '60 days', 200, 'orange'), ('Accounts', '90 days', 300, 'green')) SELECT * FROM points;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/colored-line.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'line' AS type, 4 AS marker;
WITH points(series, x, y, color) AS (VALUES ('A', 'Q1', 1, 'red'), ('A', 'Q2', 2, 'green')) SELECT * FROM points;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/colored-pie.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'pie' AS type, 4 AS marker;
WITH points(series, x, y, color) AS (VALUES ('A', 'Q1', 1, 'red'), ('A', 'Q2', 2, 'green')) SELECT * FROM points;
1 change: 1 addition & 0 deletions tests/end-to-end/fixtures/chart/colored-rangeBar.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SELECT 'dynamic' AS component, '[{"component":"chart","id":"test-chart","title":"Chart test fixture","type":"rangeBar","time":true,"marker":4},{"series":"A","x":"one","y":["2024-03-01","2024-03-05"],"color":"red"},{"series":"A","x":"two","y":["2024-03-04","2024-03-09"],"color":"green"}]' AS properties;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/colored-reference-line.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'line' AS type, 100 AS ymax, 4 AS marker;
WITH points(series, x, y, yline, label, color) AS (VALUES (NULL, NULL, NULL, 70, 'target', 'green'), ('A', 'Q1', 1, NULL, NULL, NULL), ('A', 'Q2', 2, NULL, NULL, NULL)) SELECT * FROM points;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/colored-scatter.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'scatter' AS type, 4 AS marker;
WITH points(series, x, y, color) AS (VALUES ('A', 'Q1', 1, 'red'), ('A', 'Q2', 2, 'green')) SELECT * FROM points;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/colored-treemap.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'treemap' AS type, 4 AS marker;
WITH points(series, x, y, color) AS (VALUES ('A', 'Q1', 1, 'red'), ('A', 'Q2', 2, 'green')) SELECT * FROM points;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/column.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'column' AS type, 4 AS marker;
WITH points(series, x, y) AS (VALUES ('Coding', 'Mon', 6), ('Coding', 'Tue', 4), ('Coding', 'Wed', 7)) SELECT * FROM points;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/disjoint-categories.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'bar' AS type, 4 AS marker;
WITH points(series, x, y) AS (VALUES ('A', 'X2', 10), ('A', 'X3', 30), ('B', 'X1', 25), ('B', 'X2', 20)) SELECT * FROM points;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/heatmap-categories.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'heatmap' AS type, 4 AS marker;
WITH points(series, x, y) AS (VALUES ('A', 'Q1', 1), ('A', 'Q2', 2), ('A', 'Q3', 3), ('B', 'Q2', 20), ('B', 'Q3', 30)) SELECT * FROM points;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/index.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'column' AS type, 4 AS marker;
WITH points(series, x, y) AS (VALUES ('Coding', 'Mon', 6), ('Coding', 'Tue', 4), ('Coding', 'Wed', 7)) SELECT * FROM points;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/labeled-reference-line.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'line' AS type, 4 AS marker;
WITH points(series, x, y, yline, label) AS (VALUES ('A', 'Q1', 1, NULL, NULL), ('A', 'Q2', 2, NULL, NULL), ('A', 'Q3', 3, NULL, NULL), (NULL, NULL, NULL, 2, 'limit')) SELECT * FROM points;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/line-categories.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'line' AS type, 4 AS marker;
WITH points(series, x, y) AS (VALUES ('A', 'Q1', 1), ('A', 'Q2', 2), ('A', 'Q3', 3), ('B', 'Q2', 20), ('B', 'Q3', 30)) SELECT * FROM points;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/mixed-colors.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'bar' AS type, 4 AS marker;
WITH points(series, x, y, color) AS (VALUES ('A', 'Q1', 1, NULL), ('A', 'Q2', 2, 'red')) SELECT * FROM points;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/out-of-order.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'bar' AS type, 4 AS marker;
WITH points(series, x, y) AS (VALUES ('A', 'Q3', 3), ('A', 'Q1', 1), ('A', 'Q2', 2)) SELECT * FROM points;
1 change: 1 addition & 0 deletions tests/end-to-end/fixtures/chart/range-bar.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SELECT 'dynamic' AS component, '[{"component":"chart","id":"test-chart","title":"Chart test fixture","type":"rangeBar","time":true,"marker":4},{"series":"Design","x":"Alice","y":["2024-03-01","2024-03-05"]},{"series":"Build","x":"Bob","y":["2024-03-04","2024-03-09"]}]' AS properties;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/scatter-categories.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'scatter' AS type, 4 AS marker;
WITH points(series, x, y) AS (VALUES ('A', 'Q1', 1), ('A', 'Q2', 2), ('A', 'Q3', 3), ('B', 'Q2', 20), ('B', 'Q3', 30)) SELECT * FROM points;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/stacked-categories.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'bar' AS type, TRUE AS stacked, 4 AS marker;
WITH points(series, x, y) AS (VALUES ('A', 'Q1', 1), ('A', 'Q2', 2), ('A', 'Q3', 3), ('B', 'Q2', 20), ('B', 'Q3', 30)) SELECT * FROM points;
1 change: 1 addition & 0 deletions tests/end-to-end/fixtures/chart/stacked-range-bar.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SELECT 'dynamic' AS component, '[{"component":"chart","id":"test-chart","title":"Chart test fixture","type":"rangeBar","stacked":true,"time":true,"marker":4},{"series":"Design","x":"Alice","y":["2024-03-01","2024-03-05"]},{"series":"Build","x":"Bob","y":["2024-03-04","2024-03-09"]}]' AS properties;
2 changes: 2 additions & 0 deletions tests/end-to-end/fixtures/chart/stacked-time-series.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'area' AS type, TRUE AS stacked, TRUE AS time, 4 AS marker;
WITH points(series, x, y) AS (VALUES ('CPU', '2024-01-01T00:00:00Z', 10), ('CPU', '2024-01-01T00:01:00Z', 20), ('CPU', '2024-01-01T00:02:00Z', 30), ('CPU', '2024-01-01T00:03:00Z', 40), ('GPU', '2024-01-01T00:01:00Z', 50), ('GPU', '2024-01-01T00:02:00Z', 50), ('GPU', '2024-01-01T00:03:00Z', 50)) SELECT * FROM points;
Loading