From 59c13cf2d1a434162151509fda3965079806df7b Mon Sep 17 00:00:00 2001 From: Doug Parker Date: Mon, 15 Feb 2021 20:41:28 -0800 Subject: [PATCH] Adds example which uses the `data` attribute. Refs #24. This stores several different posts in text files within the workspace. This example depends on those files via the `data` attribute and then reads them during rendering to render a new HTML page for each text file. It also generates an index page which links to all the post pages. --- examples/data/BUILD.bazel | 40 +++++++++++++++ examples/data/content/bar.txt | 1 + examples/data/content/baz.txt | 1 + examples/data/content/foo.txt | 1 + examples/data/pages.ts | 57 +++++++++++++++++++++ examples/data/test.ts | 93 +++++++++++++++++++++++++++++++++++ 6 files changed, 193 insertions(+) create mode 100644 examples/data/BUILD.bazel create mode 100644 examples/data/content/bar.txt create mode 100644 examples/data/content/baz.txt create mode 100644 examples/data/content/foo.txt create mode 100644 examples/data/pages.ts create mode 100644 examples/data/test.ts diff --git a/examples/data/BUILD.bazel b/examples/data/BUILD.bazel new file mode 100644 index 00000000..c9dd14e5 --- /dev/null +++ b/examples/data/BUILD.bazel @@ -0,0 +1,40 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_library") +load("//:index.bzl", "prerender_multi_page_bundled", "web_resources_devserver") +load("//tools:jasmine.bzl", "jasmine_node_test") + +prerender_multi_page_bundled( + name = "pages", + src = "pages.ts", + data = glob(["content/*.txt"]), + lib_deps = [ + "//common:runfiles", + "//packages/rules_prerender", + "@npm//@types/node", + ], +) + +web_resources_devserver( + name = "devserver", + resources = ":pages", +) + +ts_library( + name = "test_lib", + srcs = ["test.ts"], + testonly = True, + deps = [ + "//common:runfiles", + "//common/testing:devserver", + "//common/testing:puppeteer", + "@npm//@types/jasmine", + ], +) + +jasmine_node_test( + name = "test", + data = [ + ":devserver", + "@npm//puppeteer", + ], + deps = [":test_lib"], +) diff --git a/examples/data/content/bar.txt b/examples/data/content/bar.txt new file mode 100644 index 00000000..9953b59c --- /dev/null +++ b/examples/data/content/bar.txt @@ -0,0 +1 @@ +This is the text for the "bar" post! diff --git a/examples/data/content/baz.txt b/examples/data/content/baz.txt new file mode 100644 index 00000000..e3372009 --- /dev/null +++ b/examples/data/content/baz.txt @@ -0,0 +1 @@ +This is the text for the "baz" post! diff --git a/examples/data/content/foo.txt b/examples/data/content/foo.txt new file mode 100644 index 00000000..7c8da07d --- /dev/null +++ b/examples/data/content/foo.txt @@ -0,0 +1 @@ +This is the text for the "foo" post! diff --git a/examples/data/pages.ts b/examples/data/pages.ts new file mode 100644 index 00000000..dfa8e09b --- /dev/null +++ b/examples/data/pages.ts @@ -0,0 +1,57 @@ +import { promises as fs } from 'fs'; +import * as path from 'path'; +import { PrerenderResource } from 'rules_prerender'; +import { resolveRunfile } from 'rules_prerender/common/runfiles'; + +export default async function*(): AsyncIterable { + // Read all files under `content/` in runfiles. + const content = resolveRunfile('rules_prerender/examples/data/content/'); + const entries = await fs.readdir(content, { withFileTypes: true }); + const files = entries.filter((entry) => entry.isFile()); + + // Generate an index page which links to all posts. + yield PrerenderResource.of('/index.html', ` + + + + Data + + + +

Data

+ + + + + `.trim()); + + // Generate an HTML page with the content of each file. + for (const file of files) { + const baseName = getBaseName(file.name); + const text = await fs.readFile(path.join(content, file.name), { + encoding: 'utf8', + }); + + yield PrerenderResource.of(`/posts/${baseName}.html`, ` + + + + ${baseName} + + + +

${baseName}

+
${text.trim()}
+ + + `.trim()); + } +} + +function getBaseName(fileName: string): string { + return fileName.split('.').slice(0, -1).join('.'); +} diff --git a/examples/data/test.ts b/examples/data/test.ts new file mode 100644 index 00000000..50abd0bd --- /dev/null +++ b/examples/data/test.ts @@ -0,0 +1,93 @@ +import 'jasmine'; +import { useDevserver } from 'rules_prerender/common/testing/devserver'; +import { resolveRunfile } from 'rules_prerender/common/runfiles'; +import { useBrowser, usePage } from 'rules_prerender/common/testing/puppeteer'; + +const devserverBinary = + resolveRunfile('rules_prerender/examples/data/devserver'); + +describe('data', () => { + const server = useDevserver(devserverBinary); + const browser = useBrowser(); + const page = usePage(browser); + + describe('index page', () => { + it('renders', async () => { + await page.get().goto( + `http://${server.get().host}:${server.get().port}/`, + { waitUntil: 'load' }, + ); + + const title = await page.get().title(); + expect(title).toBe('Data'); + + const header = await page.get().$eval('h2', (el) => el.textContent); + expect(header).toBe('Data'); + + const links = await page.get().$$eval( + 'li > a', (els) => els.map((el) => el.getAttribute('href'))); + expect(links).toEqual(jasmine.arrayWithExactContents([ + '/posts/foo.html', + '/posts/bar.html', + '/posts/baz.html', + ])); + }); + }); + + describe('foo page', () => { + it('renders', async () => { + await page.get().goto( + `http://${server.get().host}:${server.get().port}/posts/foo.html`, + { waitUntil: 'load' }, + ); + + const title = await page.get().title(); + expect(title).toBe('foo'); + + const header = await page.get().$eval('h2', (el) => el.textContent); + expect(header).toBe('foo'); + + const content = await page.get().$eval( + 'article', (el) => el.textContent); + expect(content).toBe('This is the text for the "foo" post!'); + }); + }); + + describe('bar page', () => { + it('renders', async () => { + await page.get().goto( + `http://${server.get().host}:${server.get().port}/posts/bar.html`, + { waitUntil: 'load' }, + ); + + const title = await page.get().title(); + expect(title).toBe('bar'); + + const header = await page.get().$eval('h2', (el) => el.textContent); + expect(header).toBe('bar'); + + const content = await page.get().$eval( + 'article', (el) => el.textContent); + expect(content).toBe('This is the text for the "bar" post!'); + }); + }); + + describe('baz page', () => { + it('renders', async () => { + await page.get().goto( + `http://${server.get().host}:${server.get().port}/posts/baz.html`, + { waitUntil: 'load' }, + ); + + const title = await page.get().title(); + expect(title).toBe('baz'); + + const header = await page.get().$eval('h2', (el) => el.textContent); + expect(header).toBe('baz'); + + const content = await page.get().$eval( + 'article', (el) => el.textContent); + expect(content).toBe('This is the text for the "baz" post!'); + }); + }); +});