Skip to content

Commit 9e455ab

Browse files
authored
Merge branch 'main' into action-only-clean
2 parents 51a2efb + e1d02aa commit 9e455ab

File tree

21 files changed

+518
-47
lines changed

21 files changed

+518
-47
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: Close Linked Issues on PR Merge
2+
3+
on:
4+
pull_request:
5+
types: [closed]
6+
branches:
7+
- 2.0
8+
- dev-2.0
9+
10+
jobs:
11+
close_issues:
12+
if: github.event.pull_request.merged == true
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Close linked issues on non-default branches
16+
uses: processing/branch-pr-close-issue@v1
17+
with:
18+
token: ${{ secrets.GITHUB_TOKEN }}
19+
branch: dev-2.0

.github/workflows/test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ jobs:
3636
run: npm run check
3737
build:
3838
runs-on: ubuntu-latest
39+
needs: test
3940
steps:
4041
- name: Checkout your repository using git
4142
uses: actions/checkout@v4

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,8 @@ in/
2525
out/
2626
translator/
2727

28+
playwright-report/
29+
test-results/
30+
2831
# Don't commit custom dev builds
2932
public/p5.min.js

package-lock.json

Lines changed: 93 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"build:search": "tsx ./src/scripts/builders/search.ts",
1818
"build:p5-version": "tsx ./src/scripts/p5-version.ts",
1919
"custom:dev": "tsx ./src/scripts/branchTest.ts",
20-
"custom:cleanup": "tsx ./src/scripts/resetBranchTest.ts"
20+
"custom:cleanup": "tsx ./src/scripts/resetBranchTest.ts",
21+
"test:a11y": "playwright test test/a11y"
2122
},
2223
"dependencies": {
2324
"@astrojs/check": "^0.5.5",
@@ -51,7 +52,9 @@
5152
}
5253
},
5354
"devDependencies": {
55+
"@axe-core/playwright": "^4.10.2",
5456
"@codemirror/lang-javascript": "^6.2.2",
57+
"@playwright/test": "^1.54.1",
5558
"@preact/preset-vite": "^2.8.2",
5659
"@swc/html": "^1.10.9",
5760
"@testing-library/preact": "^3.2.3",

playwright.config.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { defineConfig, devices } from '@playwright/test';
2+
3+
// --- Runtime modes ---
4+
// RUN_MODE=LOCAL -> Start Astro dev server (local development)
5+
// RUN_MODE=BUILD -> Build Astro site and serve from "dist" (CI / closest to production)
6+
// RUN_MODE=REMOTE -> Do not start any local server, test directly against remote URL
7+
const RUN_MODE = process.env.RUN_MODE ?? (process.env.CI ? 'BUILD' : 'LOCAL');
8+
9+
// Allow overriding test directory via environment variable (default: ./tests)
10+
const testDir = process.env.TEST_DIR ?? './test';
11+
12+
// Base URL changes depending on the mode
13+
// LOCAL -> http://localhost:4321 (Astro dev server)
14+
// BUILD -> http://localhost:4173 (served "dist")
15+
// REMOTE -> PROD_BASE_URL (falls back to p5js.org)
16+
const baseURL =
17+
RUN_MODE === 'LOCAL'
18+
? 'http://localhost:4321'
19+
: RUN_MODE === 'BUILD'
20+
? 'http://localhost:4173'
21+
: process.env.PROD_BASE_URL ?? 'https://p5js.org';
22+
23+
24+
export default defineConfig({
25+
// Use dynamic testDir (default ./tests)
26+
testDir,
27+
outputDir: 'test-results',
28+
// Global timeout for each test to improve stability
29+
timeout: 30 * 1000,
30+
fullyParallel: true,
31+
forbidOnly: !!process.env.CI,
32+
// Retry failed tests in CI
33+
retries: process.env.CI ? 2 : 0,
34+
// Force single worker in CI to avoid port/resource conflicts
35+
workers: process.env.CI ? 1 : undefined,
36+
// Reporters: "list" for readable console logs + "html" for detailed report
37+
reporter: [
38+
['list'],
39+
['html', { outputFolder: 'playwright-report', open: 'never' }],
40+
],
41+
use: {
42+
baseURL,
43+
// Save trace only on first retry for debugging failed tests
44+
trace: 'on-first-retry',
45+
// Capture screenshot only on failure
46+
screenshot: 'only-on-failure',
47+
// Keep video only on failure in CI
48+
video: process.env.CI ? 'retain-on-failure' : 'off',
49+
},
50+
51+
// Test projects: three major engines + iPhone 15 viewport
52+
projects: [
53+
{ name: 'Desktop Chrome', use: { ...devices['Desktop Chrome'] } },
54+
{ name: 'Desktop Firefox', use: { ...devices['Desktop Firefox'] } },
55+
{ name: 'Desktop Safari', use: { ...devices['Desktop Safari'] } },
56+
{ name: 'iPhone 15', use: { ...devices['iPhone 15'] } },
57+
{ name: 'Pixel 7', use: { ...devices['Pixel 7'] } },
58+
],
59+
60+
// Start appropriate webServer depending on the mode
61+
webServer:
62+
RUN_MODE === 'LOCAL'
63+
? {
64+
// Start Astro dev server for local development
65+
command: 'npm run dev',
66+
port: 4321,
67+
reuseExistingServer: !process.env.CI,
68+
timeout: 180_000,
69+
}
70+
: RUN_MODE === 'BUILD'
71+
? {
72+
command: 'npm run build && npm run preview -- --port 4173 --host',
73+
port: 4173, // choose port OR url (not both)
74+
reuseExistingServer: !process.env.CI,
75+
timeout: 180_000,
76+
}
77+
: undefined, // REMOTE mode → no server started
78+
});
79+

src/api/OpenProcessing.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ export type OpenProcessingCurationResponse = Array<{
3333
fullname: string;
3434
}>;
3535

36+
// Selected Sketches from the 2025 curation
37+
export const priorityIds = ['2690038', '2484739', '2688829', '2689119', '2690571', '2690405','2684408' , '2693274', '2693345', '2691712']
38+
3639
/**
3740
* Get basic info for the sketches contained in a Curation
3841
* from the OpenProcessing API
@@ -47,21 +50,20 @@ export const getCurationSketches = memoize(async (
4750
const response1 = await fetch(
4851
`${openProcessingEndpoint}curation/${curationId}/sketches?${limitParam}`,
4952
);
50-
if(!response1.ok){ //log error instead of throwing error to not cache result in memoize
51-
console.error('getCurationSketches', response1.status, response1.statusText)
53+
if(!response1.ok){
54+
throw new Error(`getCurationSketches: ${response1.status} ${response1.statusText}`)
5255
}
5356
const payload1 = await response1.json();
5457

5558
const response2 = await fetch(
5659
`${openProcessingEndpoint}curation/${newCurationId}/sketches?${limitParam}`,
5760
);
58-
if(!response2.ok){ //log error instead of throwing error to not cache result in memoize
59-
console.error('getCurationSketches', response2.status, response2.statusText)
61+
if(!response2.ok){
62+
throw new Error(`getCurationSketches: ${response2.status} ${response2.statusText}`)
6063
}
6164
const payload2 = await response2.json();
6265

63-
// Selected Sketches from the 2025 curation
64-
const priorityIds = ['2690038', '2484739', '2688829', '2689119', '2690571', '2690405','2684408' , '2693274', '2693345', '2691712']
66+
6567

6668
const prioritySketches = payload2.filter(
6769
(sketch: OpenProcessingCurationResponse[number]) => priorityIds.includes(String(sketch.visualID)))
@@ -122,8 +124,7 @@ export const getSketch = memoize(
122124
// check for sketch data in Open Processing API
123125
const response = await fetch(`${openProcessingEndpoint}sketch/${id}`);
124126
if (!response.ok) {
125-
//log error instead of throwing error to not cache result in memoize
126-
console.error("getSketch", id, response.status, response.statusText);
127+
throw new Error(`getSketch: ${id} ${response.status} ${response.statusText}`)
127128
}
128129
const payload = await response.json();
129130
return payload as OpenProcessingSketchResponse;
@@ -141,8 +142,8 @@ export const getSketchSize = memoize(async (id: number) => {
141142
}
142143

143144
const response = await fetch(`${openProcessingEndpoint}sketch/${id}/code`);
144-
if(!response.ok){ //log error instead of throwing error to not cache result in memoize
145-
console.error('getSketchSize', id, response.status, response.statusText)
145+
if(!response.ok){
146+
throw new Error(`getSketchSize: ${id} ${response.status} ${response.statusText}`)
146147
}
147148
const payload = await response.json();
148149

src/components/Banner/index.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const { link, title } = entry.data;
1212
<button id="hideBanner" aria-label="Hide banner"><Icon kind="close" /></button>
1313
</div>
1414

15-
<script>
15+
<script is:inline>
1616
const banner = document.querySelector('.banner');
1717
const hideBannerBtn = document.querySelector('#hideBanner');
1818
if (banner && hideBannerBtn) {

src/components/Callout/index.astro

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@ const currentLocale = getCurrentLocale(Astro.url.pathname);
1414
const t = await getUiTranslator(currentLocale);
1515
---
1616

17-
<div class={`callout ${props.title ? 'callout-note' : ''}`}>
18-
<h5>{t('calloutTitles', props.title || "Try this!")}</h5>
17+
<section
18+
class={`callout ${props.title ? 'callout-note' : ''}`}
19+
role="region"
20+
aria-label={String(t('calloutTitles', props.title || "Try this!"))}>
21+
<div class="callout-heading" style="font-weight: bold;">
22+
{t('calloutTitles', props.title || "Try this!")}
23+
</div>
1924
<slot />
20-
</div>
25+
</section>

0 commit comments

Comments
 (0)