diff --git a/.github/scripts/fixtures/zines/zine-integration-test-fixture/guide-print.pdf b/.github/scripts/fixtures/zines/zine-integration-test-fixture/guide-print.pdf new file mode 100644 index 0000000..a2ccecc Binary files /dev/null and b/.github/scripts/fixtures/zines/zine-integration-test-fixture/guide-print.pdf differ diff --git a/.github/scripts/fixtures/zines/zine-integration-test-fixture/guide-small.pdf b/.github/scripts/fixtures/zines/zine-integration-test-fixture/guide-small.pdf new file mode 100644 index 0000000..a2ccecc Binary files /dev/null and b/.github/scripts/fixtures/zines/zine-integration-test-fixture/guide-small.pdf differ diff --git a/.github/scripts/fixtures/zines/zine-integration-test-fixture/index.md b/.github/scripts/fixtures/zines/zine-integration-test-fixture/index.md new file mode 100644 index 0000000..3f893e5 --- /dev/null +++ b/.github/scripts/fixtures/zines/zine-integration-test-fixture/index.md @@ -0,0 +1,6 @@ +--- +id: zine-integration-test-fixture +order: 13 +--- + +Use a loop to draw a playful field of shapes. Try changing the colours, sizes, and spacing together. diff --git a/.github/scripts/fixtures/zines/zine-integration-test-fixture/metadata.json b/.github/scripts/fixtures/zines/zine-integration-test-fixture/metadata.json new file mode 100644 index 0000000..9f92906 --- /dev/null +++ b/.github/scripts/fixtures/zines/zine-integration-test-fixture/metadata.json @@ -0,0 +1,18 @@ +{ + "id": "zine-integration-test-fixture", + "title": "Loops with Shapes", + "topic": "Loops", + "created_by": "Integration Test Author", + "attribution": "Integration Test Author, CC BY-SA 4.0", + "format": "workshop", + "duration": "2 hours", + "materials": "Laptop and p5.js editor", + "summary": "A compact guide to making patterns with repeated shapes.", + "cover": "cover.png", + "pdfs": [ + { "file": "guide-small.pdf", "label": "Read on screen", "file_size": "96 B" }, + { "file": "guide-print.pdf", "label": "Print and fold", "file_size": "96 B" } + ], + "license": "CC BY-SA 4.0", + "source_url": "https://discourse.processing.org/t/activity-guide-integration-test/1" +} diff --git a/.github/scripts/zine-build.test.mjs b/.github/scripts/zine-build.test.mjs new file mode 100644 index 0000000..826f1ff --- /dev/null +++ b/.github/scripts/zine-build.test.mjs @@ -0,0 +1,90 @@ +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { cpSync, copyFileSync, existsSync, readFileSync, rmSync } from 'node:fs'; +import { join, resolve } from 'node:path'; +import { execFileSync } from 'node:child_process'; + +const REPO_ROOT = resolve(new URL('../..', import.meta.url).pathname); +const WEBSITE = join(REPO_ROOT, 'pcd-website'); +const ZINES_DIR = join(WEBSITE, 'src/content/zines'); +const FIXTURE = join(REPO_ROOT, '.github/scripts/fixtures/zines/zine-integration-test-fixture'); +const SLUG = 'zine-integration-test-fixture'; +const DEST = join(ZINES_DIR, SLUG); +const DIST = join(WEBSITE, 'dist'); + +function emittedPath(href) { + assert.ok(!href.startsWith('data:'), `asset href must not be a data URI: ${href}`); + return join(DIST, new URL(href, 'https://day.processing.org').pathname.replace(/^\//, '')); +} + +function hrefForFilename(html, filename) { + const match = html.match(new RegExp(`]+href="([^"]+)"[^>]+download="${filename}"`)); + assert.ok(match, `expected a download for "${filename}"`); + return match[1]; +} + +test('a populated zine collection emits linked assets and renders entries in frontmatter order', () => { + assert.ok(!existsSync(DEST), `${DEST} already exists — refusing to overwrite`); + let created = true; + try { + cpSync(FIXTURE, DEST, { recursive: true }); + copyFileSync(join(WEBSITE, 'src/images/og-image.png'), join(DEST, 'cover.png')); + execFileSync('npm', ['run', 'build'], { cwd: WEBSITE, stdio: 'pipe' }); + + const pagePath = join(DIST, 'activity-guide', SLUG, 'index.html'); + assert.ok(existsSync(pagePath), 'the zine page should be generated'); + const page = readFileSync(pagePath, 'utf8'); + assert.match(page, /Loops with Shapes/); + assert.match(page, /View the original submission/); + + for (const filename of ['guide-small.pdf', 'guide-print.pdf']) { + assert.ok(existsSync(emittedPath(hrefForFilename(page, filename))), `${filename} should resolve to an emitted PDF`); + } + assert.match(page, /download-list__size[^>]*>96 B]+src="([^"]+)"/); + assert.ok(pageCover, 'the zine page should render a cover image'); + assert.ok(existsSync(emittedPath(pageCover[1])), 'the zine cover should be emitted'); + + const noCoverPage = readFileSync(join(DIST, 'activity-guide/zine-making-kit/index.html'), 'utf8'); + assert.match(noCoverPage, /activity-guide__cover--placeholder[^>]*>Zine Making Kit]*>519 kB\s*
  • \s*]*>Zine Making KitVariables'), + 'order 1 should render before order 2', + ); + assert.ok( + library.indexOf('Randomness') < library.indexOf(`/activity-guide/${SLUG}/`), + 'order 12 should render before order 13', + ); + assert.equal((library.match(/Submit a zine/g) ?? []).length, 11, 'each placeholder should render a submission button'); + assert.doesNotMatch(library, /Guide wanted/); + const variablesLink = library.match(/Variables<\/strong>[\s\S]*?]+href="([^"]+)"/); + assert.ok(variablesLink, 'the Variables placeholder should have a submission link'); + const variablesUrl = new URL(variablesLink[1].replaceAll('&', '&')); + assert.equal(variablesUrl.searchParams.get('title'), 'Activity Guide Submission: Variables'); + assert.match( + variablesUrl.searchParams.get('body') ?? '', + /\*\*Title:\*\* Variables/, + 'a placeholder submission should pre-populate its topic in the submission body', + ); + assert.equal(existsSync(join(DIST, 'activity-guide/variables/index.html')), false, 'placeholders should not get detail pages'); + const grid = library.match(/