Skip to content

Commit

Permalink
Move to CloudFlare, add honeypot
Browse files Browse the repository at this point in the history
  • Loading branch information
darbymanning committed Jul 15, 2024
1 parent 05a2732 commit c071089
Show file tree
Hide file tree
Showing 20 changed files with 290 additions and 83 deletions.
58 changes: 29 additions & 29 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
/** @type { import("eslint").Linter.Config } */
module.exports = {
root: true,
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:svelte/recommended',
'prettier'
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020,
extraFileExtensions: ['.svelte']
},
env: {
browser: true,
es2017: true,
node: true
},
overrides: [
{
files: ['*.svelte'],
parser: 'svelte-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser'
}
}
]
};
root: true,
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:svelte/recommended",
"prettier",
],
parser: "@typescript-eslint/parser",
plugins: ["@typescript-eslint"],
parserOptions: {
sourceType: "module",
ecmaVersion: 2020,
extraFileExtensions: [".svelte"],
},
env: {
browser: true,
es2017: true,
node: true,
},
overrides: [
{
files: ["*.svelte"],
parser: "svelte-eslint-parser",
parserOptions: {
parser: "@typescript-eslint/parser",
},
},
],
}
51 changes: 51 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: E2E Tests

env:
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
POSTMARK_API_TOKEN: ${{ secrets.POSTMARK_API_TOKEN }}

on:
workflow_dispatch:
push:
branches:
- main
pull_request:
branches:
- main

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
playwright-tests:
runs-on: ubuntu-latest
env:
POSTMARK_API_TOKEN: ${{ secrets.POSTMARK_API_TOKEN }}
PUBLIC_UUID_NAMESPACE: ${{ secrets.PUBLIC_UUID_NAMESPACE }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
SHOW_PRIVATE_DATA_PARAM: ${{ secrets.SHOW_PRIVATE_DATA_PARAM }}
EMAIL: ${{ secrets.EMAIL }}
MOBILE_NUMBER: ${{ secrets.MOBILE_NUMBER }}
ADDRESS: ${{ secrets.ADDRESS }}

steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1

- name: Install dependencies
run: bun install

- name: Install Playwright Browsers
run: bunx playwright install --with-deps

- name: Run Playwright tests
run: bun test:e2e

- name: Install Wrangler CLI
if: always()
run: npm install -g wrangler

- name: Publish Playwright Report to Cloudflare Pages
if: always()
run: wrangler pages deploy ./playwright-report --project-name=dm-portfolio-e2e-status
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ node_modules
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
10 changes: 5 additions & 5 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"semi": false,
"trailingComma": "es5",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte"],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
"semi": false,
"trailingComma": "es5",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte"],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}
41 changes: 41 additions & 0 deletions __tests__/contact.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { test, expect } from "@playwright/test"

test("allows a user to submit a contact form", async ({ page }) => {
await page.goto("/")

await page.getByRole("link", { name: "Contact" }).click()

await page.getByRole("textbox", { name: "Name", exact: true }).click()
await page.getByRole("textbox", { name: "Name", exact: true }).fill("Joe Bloggs")
await page.getByLabel("Email").click()
await page.getByLabel("Email").fill("joe@bloggs.example")
await page.getByLabel("Message").click()
await page.getByLabel("Message").fill("Ah hey man, love your site.")
await page.getByRole("button", { name: "Send message" }).click()

await expect(page.getByText("Thank you for your message.")).toBeVisible()
await expect(page.getByTestId("honeypot")).not.toBeVisible()
})

test("pretends the form is submitted when a honeypot field is filled", async ({ page }) => {
await page.goto("/")

await page.getByRole("link", { name: "Contact" }).click()

await page.getByRole("textbox", { name: "Name", exact: true }).click()
await page.getByRole("textbox", { name: "Name", exact: true }).fill("Joe Bloggs")
await page.getByLabel("Email").click()
await page.getByLabel("Email").fill("joe@bloggs.example")
await page.getByLabel("Message").click()
await page
.getByLabel("Message")
.fill("Ah hey man, love your site. I'm definitely not a bot ... heh")
await page.getByLabel("First name").fill("I'm a bot")
await page.getByRole("button", { name: "Send message" }).click()

// Pretend message is sent
await expect(page.getByText("Thank you for your message.")).toBeVisible()

// Honeypot testid is visible
await expect(page.getByTestId("honeypot")).toBeVisible()
})
Binary file modified bun.lockb
Binary file not shown.
40 changes: 23 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,43 @@
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "vite dev",
"dev": "vite dev --port ${VITE_PORT:-5173}",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check . && eslint .",
"format": "prettier --write ."
"format": "prettier --write .",
"test:e2e": "playwright test"
},
"devDependencies": {
"@sveltejs/adapter-vercel": "5.3.1",
"@sveltejs/kit": "2.5.10",
"@playwright/test": "1.45.1",
"@sveltejs/adapter-cloudflare": "4.6.1",
"@sveltejs/kit": "2.5.18",
"@sveltejs/vite-plugin-svelte": "3.1.1",
"@tailwindcss/vite": "4.0.0-alpha.15",
"@tailwindcss/vite": "4.0.0-alpha.17",
"@types/eslint": "8.56.10",
"@typescript-eslint/eslint-plugin": "7.11.0",
"@typescript-eslint/parser": "7.11.0",
"@types/node": "^20.14.10",
"@types/uuid": "10.0.0",
"@typescript-eslint/eslint-plugin": "7.16.0",
"@typescript-eslint/parser": "7.16.0",
"clsx": "2.1.1",
"dotenv": "16.4.5",
"eslint": "8.56.0",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-svelte": "2.39.0",
"eslint-plugin-svelte": "2.42.0",
"locomotive-scroll": "5.0.0-beta.12",
"postmark": "4.0.2",
"prettier": "3.2.5",
"prettier-plugin-svelte": "3.2.3",
"svelte": "5.0.0-next.144",
"svelte-check": "3.8.0",
"tailwind-merge": "2.3.0",
"postmark": "4.0.4",
"prettier": "3.3.3",
"prettier-plugin-svelte": "3.2.5",
"svelte": "5.0.0-next.182",
"svelte-check": "3.8.4",
"tailwind-merge": "2.4.0",
"tailwindcss": "4.0.0-alpha.15",
"tslib": "2.6.2",
"typescript": "5.4.5",
"vite": "5.2.12"
"tslib": "2.6.3",
"typescript": "5.5.3",
"uuid": "10.0.0",
"vite": "5.3.3"
},
"type": "module"
}
46 changes: 46 additions & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import dotenv from "dotenv"
import { defineConfig, devices } from "@playwright/test"

dotenv.config({ path: ".env.test" })

const port = 7777

export default defineConfig({
testDir: "./__tests__",
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: [["html", { outputDir: "./playwright-report" }]],
use: { trace: "on" },
projects: [
{
name: "chromium",
use: {
...devices["Desktop Chrome"],
contextOptions: { reducedMotion: "reduce" },
},
},
{
name: "firefox",
use: {
...devices["Desktop Firefox"],
contextOptions: { reducedMotion: "reduce" },
},
},
{
name: "webkit",
use: {
...devices["Desktop Safari"],
contextOptions: { reducedMotion: "reduce" },
},
},
],
webServer: {
command: process.env.CI
? `bun run build && bunx vite preview --port ${port}`
: `VITE_PORT=${port} bun dev`,
port,
reuseExistingServer: !process.env.CI,
},
})
9 changes: 9 additions & 0 deletions src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@
opacity: 100% !important;
}
}

@media (prefers-reduced-motion) {
* {
animation-duration: 0ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0ms !important;
animation-delay: 0ms !important;
}
}
}

@layer components {
Expand Down
30 changes: 27 additions & 3 deletions src/components/contact.svelte
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<script lang="ts">
import { applyAction, enhance } from "$app/forms"
import { page } from "$app/stores"
import { label_id } from "$lib/utils"
import { slide } from "svelte/transition"
let submitting = $state(false)
</script>

{#snippet input({ label, type = "text" })}
{@const id = label.toLowerCase()}
<!-- eslint-disable-next-line svelte/valid-compile -->
{@const id = label_id(label)}
{@const value = $page.form?.[id] || ""}

<label for={id} class="relative">
Expand All @@ -25,7 +25,14 @@
<section class="p-10 grid gap-2 print:hidden" id="contact">
<h1 class="heading-1" data-scroll data-scroll-speed="0.12">Contact</h1>
{#if $page.form?.sent}
<p transition:slide data-scroll data-scroll-speed="0.12">Thank you for your message.</p>
<p
transition:slide
data-scroll
data-scroll-speed="0.12"
data-testid={$page.form.honey ? "honeypot" : undefined}
>
Thank you for your message.
</p>
{:else}
<div transition:slide>
<p data-scroll data-scroll-speed="0.12">
Expand Down Expand Up @@ -58,6 +65,14 @@
{/if}
</div>
{/if}
<label for="first_name" class="🍯">First name</label>
<input
class="🍯"
id="first_name"
name="first_name"
autocomplete="off"
placeholder="First name"
/>
{@render input({ label: "Name" })}
{@render input({ label: "Email", type: "email" })}
{@render input({ label: "Message", type: "textarea" })}
Expand All @@ -73,6 +88,15 @@
</section>

<style>
.🍯 {
opacity: 0;
position: absolute;
inset: 0;
width: 0;
height: 0;
z-index: -1;
}
textarea,
input {
padding: var(--spacing-3);
Expand Down
4 changes: 2 additions & 2 deletions src/components/link.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@
</script>

<a
class={cn(classname, "flex gap-2 items-center font-mono hover:brightness-90 group")}
class={cn("flex gap-2 items-center font-mono hover:brightness-90 group", classname)}
{rel}
{target}
{href}
>
{@render children()}
<span
class="scale-125 top-0.5 rotate-45 -translate-x-3.5 relative group-hover:translate-none group-hover:rotate-none transition-all opacity-0 group-hover:opacity-100 group-focus:opacity-100 group-focus:rotate-none group-focus:translate-none"
class="sr-only pointer-events-none select-none scale-125 top-0.5 rotate-45 -translate-x-3.5 relative group-hover:translate-none group-hover:rotate-none transition-all opacity-0 group-hover:opacity-100 group-focus:opacity-100 group-focus:rotate-none group-focus:translate-none"
>&#8599;</span
>
</a>
1 change: 1 addition & 0 deletions src/components/resume.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
<Link href="mailto:{locals.private_data.email}">
{locals.private_data.email}
</Link>
<Link class="hidden print:block" href="https://darbymanning.com">darbymanning.com</Link>
</div>
<address class="whitespace-break-spaces">
{locals.private_data.address}
Expand Down
2 changes: 1 addition & 1 deletion src/components/seperator.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
let { class: classname }: Props = $props()
</script>

<hr class={cn(classname, "border-t border-gray-400/15")} />
<hr class={cn("border-t border-gray-400/15", classname)} />
Loading

0 comments on commit c071089

Please sign in to comment.