Skip to content

Commit e903a16

Browse files
author
Lea Hayes
committed
Add tests for the Generator class.
1 parent eb4f468 commit e903a16

File tree

3 files changed

+261
-2
lines changed

3 files changed

+261
-2
lines changed

Diff for: bin/generate-website.js

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import path from "path";
44

55
import Generator from "../src/Generator.js";
66
import loadStringsSync from "../src/helpers/loadStringsSync.js";
7+
import writePage from "../src/generation/writePage.js";
78

89
const PROJECT_PATH = process.cwd();
910
const PROJECT_CONFIG_SITES_PATH = path.resolve(PROJECT_PATH, "./config/sites.js");
@@ -19,6 +20,7 @@ const PROJECT_DIST_PATH = path.resolve(PROJECT_PATH, "./dist");
1920
sites,
2021
stringsByLanguage,
2122
defaultTemplatesPath: PROJECT_DEFAULT_TEMPLATES_PATH,
23+
writePage,
2224
});
2325

2426
console.time("generate website");

Diff for: src/Generator.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import addUrlAttributes from "./generation/addUrlAttributes.js";
99
import createPagesFromContentSources from "./generation/createPagesFromContentSources.js";
1010
import fetchSiteData from "./generation/fetchSiteData.js";
1111
import renderSitePages from "./generation/renderSitePages.js";
12-
import writePage from "./generation/writePage.js";
1312

1413
export default class Generator {
1514
constructor(options) {
@@ -18,6 +17,7 @@ export default class Generator {
1817
this.sitesByName = Object.fromEntries(this.sites.map(site => ([ site.name, site ])));
1918
this.stringsByLanguage = options.stringsByLanguage;
2019
this.defaultTemplatesPath = options.defaultTemplatesPath;
20+
this.writePage = options.writePage;
2121
}
2222

2323
async generate(outputPath) {
@@ -62,7 +62,7 @@ export default class Generator {
6262
const renderer = await createRenderer(templatesPath, processedSite.data, processedSite.hooks?.setupNunjucks);
6363

6464
const siteOutputPath = `${outputPath}/${processedSite.name}`;
65-
await renderSitePages(siteOutputPath, processedSite, renderer, writePage);
65+
await renderSitePages(siteOutputPath, processedSite, renderer, this.writePage);
6666

6767
processedSite.hooks?.afterPagesWritten?.call(null, { siteOutputPath, processedSite });
6868
}

Diff for: src/Generator.spec.js

+257
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
import fs from "fs-extra";
2+
3+
import Generator from "./Generator.js";
4+
5+
const FAKE_CONTENT_SOURCES = [
6+
{
7+
name: "firstSource",
8+
fetchData: async (site) => ({ foo: site.title }),
9+
createPages: (site, data) => ([
10+
{
11+
id: "contact",
12+
layout: "layouts/simple",
13+
uri: "contact",
14+
title: `Contact page (${site.name})`,
15+
pagination: {
16+
data: [ 1, 2, 3 ],
17+
size: 2,
18+
}
19+
},
20+
]),
21+
},
22+
{
23+
name: "secondSource",
24+
fetchData: async (site) => ({ bar: 42 }),
25+
createPages: (site, data) => ([
26+
{
27+
id: "home",
28+
layout: "layouts/simple",
29+
uri: "",
30+
title: `Home page (${site.name})`,
31+
},
32+
]),
33+
},
34+
];
35+
36+
function createExampleOptions(options = {}) {
37+
const { hooks } = options;
38+
return {
39+
sites: [
40+
{
41+
name: "en",
42+
title: "Example English Website",
43+
baseUrl: "/en/",
44+
absoluteBaseUrl: "https://localhost:1234/en/",
45+
sources: FAKE_CONTENT_SOURCES,
46+
templatesPath: "tests/examples/templates",
47+
hooks,
48+
},
49+
{
50+
name: "cy",
51+
title: "Example Welsh Website",
52+
baseUrl: "/cy/",
53+
absoluteBaseUrl: "https://localhost:1234/cy/",
54+
sources: FAKE_CONTENT_SOURCES,
55+
templatesPath: "tests/examples/templates",
56+
hooks,
57+
},
58+
],
59+
60+
stringsByLanguage: {
61+
en: {
62+
"main": {
63+
"exampleWithKey": "Keys are good for situations where there are large volumes of text...",
64+
},
65+
},
66+
cy: {
67+
"main": {
68+
"exampleWithKey": "Mae allweddi yn dda ar gyfer sefyllfaoedd lle mae llawer iawn o destun...",
69+
},
70+
},
71+
},
72+
73+
writePage: options.writePage ?? (async () => {}),
74+
};
75+
}
76+
77+
describe("Generator", () => {
78+
describe("x1234 async generate(outputPath)", () => {
79+
it.each([
80+
[ "" ],
81+
[ null ],
82+
])("throws error when output path is not provided (%s)", async (outputPath) => {
83+
const options = createExampleOptions();
84+
const generator = new Generator(options);
85+
86+
await expect(generator.generate(outputPath))
87+
.rejects
88+
.toThrow("Invalid outputPath");
89+
});
90+
91+
it("throws error when output path would be root of storage", async () => {
92+
const options = createExampleOptions();
93+
const generator = new Generator(options);
94+
95+
await expect(generator.generate("/"))
96+
.rejects
97+
.toThrow("Invalid outputPath");
98+
});
99+
100+
it("calls hook `preprocessDataForSite` to preprocess data", async () => {
101+
let hookCalledWithContext = [];
102+
const hooks = {
103+
preprocessDataForSite: (context) => {
104+
hookCalledWithContext.push(context);
105+
},
106+
};
107+
108+
const options = createExampleOptions({ hooks });
109+
const generator = new Generator(options);
110+
111+
await generator.generate("dist/test/generate");
112+
113+
expect(hookCalledWithContext[0].site.name).toBe("en");
114+
expect(hookCalledWithContext[1].site.name).toBe("cy");
115+
});
116+
117+
it("adds source data to site data object", async () => {
118+
let hookCalledWithContext = [];
119+
const hooks = {
120+
preprocessDataForSite: (context) => {
121+
hookCalledWithContext.push(context);
122+
},
123+
};
124+
125+
const options = createExampleOptions({ hooks });
126+
const generator = new Generator(options);
127+
await generator.generate("dist/test/generate");
128+
129+
expect(hookCalledWithContext[0].data.firstSource.foo).toEqual("Example English Website");
130+
expect(hookCalledWithContext[0].data.secondSource.bar).toEqual(42);
131+
});
132+
133+
it("adds `stringsByLanguage` to site data object", async () => {
134+
let hookCalledWithContext = [];
135+
const hooks = {
136+
preprocessDataForSite: (context) => {
137+
hookCalledWithContext.push(context);
138+
},
139+
};
140+
141+
const options = createExampleOptions({ hooks });
142+
const generator = new Generator(options);
143+
144+
await generator.generate("dist/test/generate");
145+
146+
expect(hookCalledWithContext[0].data.stringsByLanguage).toEqual(options.stringsByLanguage);
147+
});
148+
149+
it("calls hook `applyTransformsToPages` to transform page objects", async () => {
150+
let hookCalledWithContext = [];
151+
const hooks = {
152+
applyTransformsToPages: (context) => {
153+
hookCalledWithContext.push(context);
154+
},
155+
};
156+
157+
const options = createExampleOptions({ hooks });
158+
const generator = new Generator(options);
159+
160+
await generator.generate("dist/test/generate");
161+
162+
expect(hookCalledWithContext[0].pages.length).toBe(2);
163+
expect(hookCalledWithContext[0].site.name).toBe("en");
164+
expect(hookCalledWithContext[0].data.secondSource.bar).toBe(42);
165+
});
166+
167+
it("adds `url` and `absoluteUrl` attributes to page objects", async () => {
168+
let hookCalledWithContext = [];
169+
const hooks = {
170+
applyTransformsToPages: (context) => {
171+
hookCalledWithContext.push(context);
172+
},
173+
};
174+
175+
const options = createExampleOptions({ hooks });
176+
const generator = new Generator(options);
177+
178+
await generator.generate("dist/test/generate");
179+
180+
const homePage = hookCalledWithContext[0].pages.find(page => page.uri === "");
181+
expect(homePage.url).toBe("/en/");
182+
expect(homePage.absoluteUrl).toBe("https://localhost:1234/en/");
183+
184+
const contactPage = hookCalledWithContext[0].pages.find(page => page.uri === "contact");
185+
expect(contactPage.url).toBe("/en/contact");
186+
expect(contactPage.absoluteUrl).toBe("https://localhost:1234/en/contact");
187+
});
188+
189+
it("removes the previous output directory", async () => {
190+
await fs.ensureFile("dist/test/removes-output/test.txt");
191+
192+
const options = createExampleOptions();
193+
const generator = new Generator(options);
194+
195+
expect(fs.existsSync("dist/test/removes-output/test.txt")).toBe(true);
196+
await generator.generate("dist/test/removes-output");
197+
expect(fs.existsSync("dist/test/removes-output/test.txt")).toBe(false);
198+
});
199+
200+
it("renders and writes each page", async () => {
201+
let writtenPages = [];
202+
const writePage = async (path, content) => {
203+
writtenPages.push([ path, content ]);
204+
};
205+
206+
const options = createExampleOptions({ writePage });
207+
const generator = new Generator(options);
208+
209+
await generator.generate("dist/test/generate");
210+
211+
expect(writtenPages).toContainEqual([
212+
"dist/test/generate/en/index.html",
213+
"Page title: Home page (en)\n",
214+
]);
215+
expect(writtenPages).toContainEqual([
216+
"dist/test/generate/en/contact/index.html",
217+
"Page title: Contact page (en)\n",
218+
]);
219+
expect(writtenPages).toContainEqual([
220+
"dist/test/generate/en/contact/2/index.html",
221+
"Page title: Contact page (en)\n",
222+
]);
223+
224+
expect(writtenPages).toContainEqual([
225+
"dist/test/generate/cy/index.html",
226+
"Page title: Home page (cy)\n",
227+
]);
228+
expect(writtenPages).toContainEqual([
229+
"dist/test/generate/cy/contact/index.html",
230+
"Page title: Contact page (cy)\n",
231+
]);
232+
expect(writtenPages).toContainEqual([
233+
"dist/test/generate/cy/contact/2/index.html",
234+
"Page title: Contact page (cy)\n",
235+
]);
236+
});
237+
238+
it("calls hook `afterPagesWritten` after all pages have been written", async () => {
239+
let hookCalledWithContext = [];
240+
const hooks = {
241+
afterPagesWritten: (context) => {
242+
hookCalledWithContext.push(context);
243+
},
244+
};
245+
246+
const options = createExampleOptions({ hooks });
247+
const generator = new Generator(options);
248+
249+
await generator.generate("dist/test/generate");
250+
251+
expect(hookCalledWithContext[0].siteOutputPath).toBe("dist/test/generate/en");
252+
expect(hookCalledWithContext[0].processedSite.name).toBe("en");
253+
expect(hookCalledWithContext[1].siteOutputPath).toBe("dist/test/generate/cy");
254+
expect(hookCalledWithContext[1].processedSite.name).toBe("cy");
255+
});
256+
});
257+
});

0 commit comments

Comments
 (0)