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
18 changes: 18 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Normalize line endings: store text as LF in the repo and in working trees,
# regardless of each contributor's core.autocrlf setting.
* text=auto eol=lf

# Binary assets — never touch line endings
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.webp binary
*.woff binary
*.woff2 binary
*.ttf binary
*.eot binary
*.zip binary
*.crx binary
*.xpi binary
26 changes: 21 additions & 5 deletions .github/workflows/css-selectors.yaml
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
name: CSS Selectors
name: CSS Selectors (live canary)

# Hits live royalroad.com to verify our CSS selectors still match the real page
# layout. It depends on a third-party site being up and unchanged, so it runs on
# PRs into dev/main (where a layout drift would matter before a release) and on
# demand. When it fails, refresh the selectors in src/lib/config/defaults.ts and
# the fixtures in src/tests/fixtures/.
on:
pull_request:
branches: [main]
branches: [main, dev]
types: [opened, reopened, synchronize, ready_for_review]
paths:
- 'src/**'
- 'tests/**'
- 'playwright.config.ts'
- 'package.json'
- 'pnpm-lock.yaml'
- 'wxt.config.ts'
workflow_dispatch:

jobs:
css-selectors:
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
runs-on: ubuntu-latest
timeout-minutes: 15

# Stop needrestart from prompting during `playwright install --with-deps`
# on Ubuntu 24.04, which otherwise hangs the apt step indefinitely.
env:
NEEDRESTART_MODE: a
NEEDRESTART_SUSPEND: 1

steps:
- uses: actions/checkout@v4
Expand All @@ -37,5 +49,9 @@ jobs:
- name: Install Playwright Browsers
run: pnpm playwright install --with-deps chromium

- name: Run Playwright tests
run: pnpm test
# The shared fixture loads the unpacked extension, so build it first.
- name: Build extension (Chrome MV3)
run: pnpm build

- name: Run live selector canary
run: pnpm test:canary
52 changes: 52 additions & 0 deletions .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: E2E Tests

on:
pull_request:
branches: [main, dev]
types: [opened, reopened, synchronize, ready_for_review]
paths:
- 'src/**'
- 'playwright.config.ts'
- 'package.json'
- 'pnpm-lock.yaml'
- 'wxt.config.ts'

jobs:
e2e:
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
runs-on: ubuntu-latest
timeout-minutes: 15

# Stop needrestart from prompting during `playwright install --with-deps`
# on Ubuntu 24.04, which otherwise hangs the apt step indefinitely.
env:
NEEDRESTART_MODE: a
NEEDRESTART_SUSPEND: 1

steps:
- uses: actions/checkout@v4

- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10

- name: Setup node.js
uses: actions/setup-node@v4
with:
node-version: lts/*
cache: "pnpm"

- name: Install dependencies
run: pnpm install --frozen-lockfile

# The e2e fixture loads an unpacked extension, which needs a real
# Chromium with the new headless shell (channel: "chromium").
- name: Install Playwright Browsers
run: pnpm playwright install --with-deps chromium

- name: Build extension (Chrome MV3)
run: pnpm build

- name: Run mocked-page E2E tests (Playwright)
run: pnpm test
2 changes: 1 addition & 1 deletion .github/workflows/prettier-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Prettier Check

on:
pull_request:
branches: [main]
branches: [main, dev]
types: [opened, reopened, synchronize, ready_for_review]

jobs:
Expand Down
107 changes: 107 additions & 0 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
name: Publish

on:
push:
branches: [main]
paths-ignore:
- '**.md'
- 'docs/**'
- '.github/**'
- '.gitignore'
- '.editorconfig'
- '.prettierrc'
workflow_dispatch:

jobs:
check:
runs-on: ubuntu-latest
outputs:
should_publish: ${{ steps.check.outputs.should_publish }}
version: ${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Read version from package.json
id: version
run: echo "version=$(jq -r .version package.json)" >> "$GITHUB_OUTPUT"

# The semver workflow already enforces a version bump on every PR to
# main, but guard on the tag so re-runs and non-version pushes (or a
# manual dispatch) never submit the same version twice.
- name: Skip if version already released
id: check
run: |
if git rev-parse "v${{ steps.version.outputs.version }}" >/dev/null 2>&1; then
echo "Tag v${{ steps.version.outputs.version }} already exists - nothing to publish."
echo "should_publish=false" >> "$GITHUB_OUTPUT"
else
echo "should_publish=true" >> "$GITHUB_OUTPUT"
fi

publish:
needs: check
if: needs.check.outputs.should_publish == 'true'
runs-on: ubuntu-latest
permissions:
contents: write
env:
VERSION: ${{ needs.check.outputs.version }}
# Chrome only runs once a refresh token secret is present. Until then
# Firefox publishes on its own and the Chrome step is skipped.
HAS_CHROME_TOKEN: ${{ secrets.CHROME_REFRESH_TOKEN != '' }}
steps:
- uses: actions/checkout@v4

- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: lts/*
cache: 'pnpm'

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build & zip (Chrome)
run: pnpm zip

- name: Build & zip (Firefox + sources)
run: pnpm zip:firefox

- name: Submit to Firefox Add-ons
run: |
pnpm wxt submit \
--firefox-zip .output/*-firefox.zip \
--firefox-sources-zip .output/*-sources.zip
env:
FIREFOX_EXTENSION_ID: ${{ secrets.FIREFOX_EXTENSION_ID }}
FIREFOX_JWT_ISSUER: ${{ secrets.FIREFOX_JWT_ISSUER }}
FIREFOX_JWT_SECRET: ${{ secrets.FIREFOX_JWT_SECRET }}
FIREFOX_CHANNEL: ${{ secrets.FIREFOX_CHANNEL }}

- name: Submit to Chrome Web Store
if: env.HAS_CHROME_TOKEN == 'true'
run: |
pnpm wxt submit \
--chrome-zip .output/*-chrome.zip
env:
CHROME_EXTENSION_ID: ${{ secrets.CHROME_EXTENSION_ID }}
CHROME_CLIENT_ID: ${{ secrets.CHROME_CLIENT_ID }}
CHROME_CLIENT_SECRET: ${{ secrets.CHROME_CLIENT_SECRET }}
CHROME_REFRESH_TOKEN: ${{ secrets.CHROME_REFRESH_TOKEN }}
CHROME_PUBLISH_TARGET: ${{ secrets.CHROME_PUBLISH_TARGET }}
CHROME_SKIP_SUBMIT_REVIEW: ${{ secrets.CHROME_SKIP_SUBMIT_REVIEW }}

- name: Tag and create GitHub release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git tag "v$VERSION"
git push origin "v$VERSION"
gh release create "v$VERSION" --title "v$VERSION" --generate-notes
38 changes: 38 additions & 0 deletions .github/workflows/unit.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Unit Tests

on:
pull_request:
branches: [main, dev]
types: [opened, reopened, synchronize, ready_for_review]
paths:
- 'src/**'
- 'vitest.config.ts'
- 'package.json'
- 'pnpm-lock.yaml'
- 'wxt.config.ts'

jobs:
unit:
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
runs-on: ubuntu-latest
timeout-minutes: 10

steps:
- uses: actions/checkout@v4

- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10

- name: Setup node.js
uses: actions/setup-node@v4
with:
node-version: lts/*
cache: "pnpm"

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Run unit + component tests (Vitest)
run: pnpm test:unit
Binary file modified docs/basic_settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 23 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "royalrefresh",
"version": "1.5.0",
"version": "1.7.1",
"description": "A web extension for royalroad.com. For people who juggle multiple stories",
"main": "background.js",
"directories": {
Expand All @@ -10,17 +10,20 @@
"scripts": {
"dev": "wxt",
"dev:firefox": "wxt -b firefox",
"dev:android": "node scripts/dev-android.js",
"dev:android": "node scripts/dev-android.ts",
"build": "wxt build",
"build:firefox": "wxt build -b firefox",
"zip": "wxt zip",
"zip:firefox": "wxt zip -b firefox",
"check": "svelte-check --tsconfig ./tsconfig.json",
"postinstall": "wxt prepare",
"lint": "pnpm build && web-ext lint --source-dir .output/firefox-mv2",
"test": "playwright test --reporter=list",
"test": "playwright test --project=e2e --reporter=list",
"test:ui": "playwright test --ui",
"test:detailed": "playwright test",
"test:detailed": "playwright test --project=e2e",
"test:canary": "playwright test --project=canary --reporter=list",
"test:unit": "vitest run",
"test:unit:watch": "vitest",
"format": "prettier --write src/",
"format:check": "prettier --check src/"
},
Expand All @@ -44,21 +47,27 @@
},
"homepage": "https://github.com/Seismix/royalrefresh#readme",
"devDependencies": {
"@playwright/test": "^1.56.1",
"@tsconfig/svelte": "^5.0.5",
"@playwright/test": "^1.61.0",
"@sveltejs/vite-plugin-svelte": "^7.1.2",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/svelte": "^5.3.1",
"@tsconfig/svelte": "^5.0.6",
"@types/firefox-webext-browser": "^143.0.0",
"@types/node": "^24.9.2",
"@types/node": "^25.0.9",
"@vitest/coverage-v8": "^3.2.6",
"@wxt-dev/module-svelte": "^2.0.4",
"prettier": "^3.6.2",
"prettier-plugin-svelte": "^3.4.0",
"svelte": "^5.43.0",
"svelte-check": "^4.3.3",
"happy-dom": "^20.10.6",
"prettier": "^3.8.0",
"prettier-plugin-svelte": "^3.4.1",
"svelte": "^5.47.1",
"svelte-check": "^4.3.5",
"tslib": "^2.8.1",
"typescript": "^5.9.3",
"web-ext": "^9.1.0",
"wxt": "^0.20.11"
"vitest": "^3.2.6",
"web-ext": "^9.2.0",
"wxt": "^0.20.13"
},
"dependencies": {
"dompurify": "^3.3.0"
"dompurify": "^3.3.1"
}
}
21 changes: 14 additions & 7 deletions playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import { defineConfig, devices } from "@playwright/test"
*/
export default defineConfig({
testDir: "./src/tests",
/* Vitest owns *.unit.test.ts / *.svelte.test.ts — keep Playwright from
* collecting them so the two runners never double-collect files. */
testIgnore: ["**/*.unit.test.ts", "**/*.svelte.test.ts"],
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
Expand All @@ -31,16 +34,20 @@ export default defineConfig({
trace: "on-first-retry",
},

/* Configure projects for major browsers */
/* Two projects, selected via --project:
* - "e2e" : mocked-page extension tests (zero network) — runs on every PR.
* - "canary" : live RoyalRoad selector check — scheduled / manual only.
* `pnpm test` defaults to the e2e project so the live canary never blocks PRs. */
projects: [
{
name: "chromium",
name: "e2e",
testMatch: /e2e\.test\.ts/,
use: { ...devices["Desktop Chrome"] },
},
{
name: "canary",
testMatch: /selectors\.test\.ts/,
use: { ...devices["Desktop Chrome"] },
},

// {
// name: "firefox",
// use: { ...devices["Desktop Firefox"] },
// },
],
})
Loading
Loading