Skip to content

Commit

Permalink
Merge pull request #97 from phonzammi/phonzammi/dev
Browse files Browse the repository at this point in the history
Refactor `examples` & add `e2e-tests`
  • Loading branch information
phonzammi committed Jul 1, 2024
2 parents 4d4ad4f + 1e30902 commit 530d5f5
Show file tree
Hide file tree
Showing 58 changed files with 805 additions and 372 deletions.
32 changes: 0 additions & 32 deletions .github/workflows/build.yml

This file was deleted.

43 changes: 43 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: CI
on: [push, pull_request]

jobs:
test:
# Prevent workflow being run twice, https://github.com/orgs/community/discussions/57827#discussioncomment-6579237
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name

name: ${{ matrix.cmd }} (${{ matrix.os }})

runs-on: ${{ matrix.os }}

strategy:
# Don't cancel other matrix operations if one fails
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
cmd:
- pnpm run test:e2e
- pnpm run test:types
# `exclude` docs & alternatives:
# - https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategymatrixexclude
# - https://stackoverflow.com/questions/68994484/how-to-skip-a-configuration-of-a-matrix-with-github-actions/68994907#68994907
# - https://stackoverflow.com/questions/66025220/paired-values-in-github-actions-matrix/68940067#68940067
exclude:
- os: windows-latest
cmd: pnpm run test:types

steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: "pnpm"

- run: pnpm install
- run: pnpm exec playwright install chromium
- run: pnpm run build

- run: ${{ matrix.cmd }}
14 changes: 0 additions & 14 deletions examples/basic/README.md

This file was deleted.

2 changes: 2 additions & 0 deletions examples/full/.test-dev.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { testRun } from "./.testRun";
testRun("pnpm run dev");
2 changes: 2 additions & 0 deletions examples/full/.test-preview.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { testRun } from "./.testRun";
testRun("pnpm run preview");
163 changes: 163 additions & 0 deletions examples/full/.testRun.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
export { testRun };

import { test, expect, run, fetchHtml, page, getServerUrl, autoRetry, partRegex } from "@brillout/test-e2e";

let isProd: boolean;

function testRun(cmd: `pnpm run ${"dev" | "preview"}`) {
run(cmd);

isProd = cmd !== "pnpm run dev";

const title = "My Vike + Solid App";
testUrl({
url: "/",
title,
text: "Rendered to HTML.",
counter: true,
});

testUrl({
url: "/star-wars",
title: "6 Star Wars Movies",
text: "A New Hope",
});

testUrl({
url: "/star-wars/3",
title: "Return of the Jedi",
text: "1983-05-25",
});

const textNoSSR = "This page is rendered only in the browser";
testUrl({
url: "/without-ssr",
title: "No SSR",
text: textNoSSR,
counter: true,
noSSR: true,
});

testNavigationBetweenWithSSRAndWithoutSSR();
}

function testNavigationBetweenWithSSRAndWithoutSSR() {
const textWithSSR = "Rendered to HTML.";
const textWithoutSSR = "It isn't rendered to HTML";

const url = "/without-ssr";
test(url + " isn't rendered to HTML", async () => {
const html = await fetchHtml(url);
expect(html).toContain('<div id="root"></div>');
expect(html).not.toContain(textWithoutSSR);
await page.goto(getServerUrl() + url);
await testCounter();
const body = await page.textContent("body");
expect(body).toContain(textWithoutSSR);
});

test("Switch between SSR and non-SSR page", async () => {
let body: string | null;
const t1 = textWithoutSSR;
const t2 = textWithSSR;

body = await page.textContent("body");
expect(body).toContain(t1);
expect(body).not.toContain(t2);
ensureWasClientSideRouted("/pages/without-ssr");

await page.click('a:has-text("Welcome")');
await testCounter();
body = await page.textContent("body");
expect(body).toContain(t2);
expect(body).not.toContain(t1);
ensureWasClientSideRouted("/pages/without-ssr");

await page.click('a:has-text("Without SSR")');
await testCounter();
body = await page.textContent("body");
expect(body).toContain(t1);
expect(body).not.toContain(t2);
ensureWasClientSideRouted("/pages/without-ssr");
});
}

function testUrl({
url,
title,
text,
counter,
noSSR,
}: {
url: string;
title: string;
text: string;
counter?: true;
noSSR?: true;
}) {
test(url + " (HTML)", async () => {
const html = await fetchHtml(url);
if (!noSSR) {
expect(html).toContain(text);
}
expect(getTitle(html)).toBe(title);
const hash = /[a-zA-Z0-9_-]+/;
const dataHkHash = /[0-9-]+/;

if (!isProd) {
expect(html).toMatch(partRegex`<link data-hk="${dataHkHash}" rel="icon" href="/assets/logo.svg">`);
} else {
expect(html).toMatch(partRegex`<link data-hk="${dataHkHash}" rel="icon" href="/assets/static/logo.${hash}.svg">`);
}
});
test(url + " (Hydration)", async () => {
await page.goto(getServerUrl() + url);
if (counter) {
await testCounter();
}
const body = await page.textContent("body");
expect(body).toContain(text);
});
}

function getTitle(html: string) {
const title = html.match(/<title>(.*?)<\/title>/i)?.[1];
return title;
}

async function testCounter() {
// autoRetry() for awaiting client-side code loading & executing
await autoRetry(
async () => {
expect(await page.textContent("button")).toBe("Counter 0");
await page.click("button");
expect(await page.textContent("button")).toContain("Counter 1");
},
{ timeout: 5 * 1000 },
);
}

/** Ensure page wasn't server-side routed.
*
* Examples:
* await ensureWasClientSideRouted('/pages/index')
* await ensureWasClientSideRouted('/pages/about')
*/
async function ensureWasClientSideRouted(pageIdFirst: `/pages/${string}`) {
// Check whether the HTML is from the first page before Client-side Routing.
// page.content() doesn't return the original HTML (it dumps the DOM to HTML).
// Therefore only the serialized pageContext tell us the original HTML.
const html = await page.content();
const pageId = findFirstPageId(html);
expect(pageId).toBe(pageIdFirst);
}
function findFirstPageId(html: string) {
expect(html).toContain('<script id="vike_pageContext" type="application/json">');
expect(html).toContain("_pageId");
expect(html.split("_pageId").length).toBe(2);
const match = partRegex`"_pageId":"${/([^"]+)/}"`.exec(html);
expect(match).toBeTruthy();
const pageId = match![1];
expect(pageId).toBeTruthy();
return pageId;
}
15 changes: 15 additions & 0 deletions examples/full/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Full-fledged example of using `vike-solid`, showcasing:

- [Layout](https://vike.dev/Layout)
- Rendering to `<head>`
- Fetching data with [`data()`](https://vike.dev/data) hook
- [Toggling SSR](https://vike.dev/ssr) on a per-page basis.
- [configs](https://vike.dev/config)
- [Error page](https://vike.dev/error-page)

```bash
git clone git@github.com:vikejs/vike-solid
cd vike-solid/examples/full/
pnpm install
pnpm run dev
```
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion examples/basic/package.json → examples/full/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"preview": "vite build && vite preview",
"test": "tsc --noEmit"
},
"dependencies": {
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import "../layouts/style.css";
import logoUrl from "../assets/logo.svg";
import { Link } from "../components/Link.js";
import { Link } from "../components/Link";
import type { JSX } from "solid-js";

export function Layout(props: { children?: JSX.Element }) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import type { Config } from "vike/types";
// Default config (can be overridden by pages)
export default {
// <title>
title: "My Vike Solid App",
title: "My Vike + Solid App",
extends: vikeSolid,
} satisfies Config;
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const ClientOnlyCounterSlow = clientOnly(async () => {
export default function Page() {
return (
<>
<h1>My vike-solid app</h1>
<h1>My Vike + Solid App</h1>
This page is:
<ul>
<li>Rendered to HTML.</li>
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
{
"private": true,
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"test": "tsc --noEmit"
"preview": "vite build && vite preview"
},
"dependencies": {
"solid-js": "^1.8.17",
"vike": "^0.4.177",
"vike-solid": "link:vike-solid"
},
"devDependencies": {
"typescript": "^5.4.5",
"vite": "^5.3.1"
"vite": "^5.2.9"
},
"type": "module"
}
11 changes: 11 additions & 0 deletions examples/minimal/pages/+config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export { config };

import vikeSolid from "vike-solid/config";
import { Layout } from "./Layout";

const config = {
// https://vike.dev/Layout
Layout: Layout,
// https://vike.dev/extends
extends: vikeSolid,
};
14 changes: 14 additions & 0 deletions examples/minimal/pages/Layout.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
body {
margin: 0;
font-family: sans-serif;
}
* {
box-sizing: border-box;
}
a {
text-decoration: none;
}

.navitem {
padding: 3px;
}
Loading

0 comments on commit 530d5f5

Please sign in to comment.