Repository: 11ty/eleventy
Pull request #942 (2020-02-17 04:17:59)

Refactor `renderData` so that it works


Patch:
diff --git a/package.json b/package.json
index ecb8767a..b5e01b31 100755
--- a/package.json
+++ b/package.json
@@ -60,7 +60,7 @@
   "homepage": "https://www.11ty.dev/",
   "ava": {
     "babel": true,
-    "failFast": true,
+    "failFast": false,
     "files": [
       "./test/*.js"
     ],
diff --git a/src/Template.js b/src/Template.js
index 7a8a6e16..e4c159a7 100644
--- a/src/Template.js
+++ b/src/Template.js
@@ -73,7 +73,7 @@ class Template extends TemplateContent {
   }
 
   getLayout(layoutKey) {
-    if(!this._layout || layoutKey !== this._layoutKey) {
+    if (!this._layout || layoutKey !== this._layoutKey) {
       this._layoutKey = layoutKey;
       this._layout = TemplateLayout.getTemplate(
         layoutKey,
@@ -85,7 +85,7 @@ class Template extends TemplateContent {
   }
 
   async getLayoutChain() {
-    if(!this._layout) {
+    if (!this._layout) {
       await this.getData();
     }
 
@@ -159,7 +159,6 @@ class Template extends TemplateContent {
     return link.toHref();
   }
 
-  // TODO check for conflicts, see if file already exists?
   async getOutputPath(data) {
     let uri = await this.getOutputLink(data);
 
@@ -294,42 +293,6 @@ class Template extends TemplateContent {
     return data;
   }
 
-  async addPageRenderedData(data) {
-    if (!("page" in data)) {
-      data.page = {};
-    }
-
-    let newUrl = await this.getOutputHref(data);
-    if ("page" in data && "url" in data.page) {
-      if (data.page.url !== newUrl) {
-        debug(
-          "Warning: data.page.url is in use (%o) will be overwritten with: %o",
-          data.page.url,
-          newUrl
-        );
-      }
-    }
-
-    data.page.url = newUrl;
-    data.page.outputPath = await this.getOutputPath(data);
-
-    return data;
-  }
-
-  // getData (with renderData and page.url added)
-  async getRenderedData() {
-    let data = await this.getData();
-    data = await this.addPageRenderedData(data);
-
-    if (data.renderData) {
-      data.renderData = await this.mapDataAsRenderedTemplates(
-        data.renderData,
-        data
-      );
-    }
-    return data;
-  }
-
   async renderLayout(tmpl, tmplData) {
     let layoutKey = tmplData[tmpl.config.keys.layout];
     let layout = this.getLayout(layoutKey);
@@ -354,10 +317,12 @@ class Template extends TemplateContent {
     return super.render(str, data, bypassMarkdown);
   }
 
+  // TODO at least some of this isn’t being used in the normal build
+  // Render is used for `renderData` and `permalink` but otherwise `renderPageEntry` is being used
   async render(data) {
     debugDev("%o render()", this.inputPath);
     if (!data) {
-      data = await this.getRenderedData();
+      throw new Error("`data` needs to be passed into render()");
     }
 
     if (!this.wrapWithLayouts && data[this.config.keys.layout]) {
@@ -407,6 +372,13 @@ class Template extends TemplateContent {
       data.page.url = await this.getOutputHref(data);
       data.page.outputPath = await this.getOutputPath(data);
 
+      if ("renderData" in data) {
+        data.renderData = await this.mapDataAsRenderedTemplates(
+          data.renderData,
+          data
+        );
+      }
+
       results.push({
         template: this,
         inputPath: this.inputPath,
@@ -438,7 +410,7 @@ class Template extends TemplateContent {
       let pageNumber = 0;
       for (let page of templates) {
         // TODO try to reuse data instead of a new copy
-        let pageData = await page.getRenderedData();
+        let pageData = Object.assign({}, await page.getData());
 
         // Issue #115
         if (data.collections) {
@@ -448,6 +420,13 @@ class Template extends TemplateContent {
         pageData.page.url = await page.getOutputHref(pageData);
         pageData.page.outputPath = await page.getOutputPath(pageData);
 
+        if ("renderData" in pageData) {
+          pageData.renderData = await page.mapDataAsRenderedTemplates(
+            pageData.renderData,
+            pageData
+          );
+        }
+
         results.push({
           template: page,
           inputPath: this.inputPath,
@@ -560,6 +539,7 @@ class Template extends TemplateContent {
     return Promise.all(promises);
   }
 
+  // TODO is this still used by anything but tests?
   async write(outputPath, data) {
     let templates = await this.getRenderedTemplates(data);
     let promises = [];
diff --git a/src/TemplateMap.js b/src/TemplateMap.js
index 72013231..318046cf 100644
--- a/src/TemplateMap.js
+++ b/src/TemplateMap.js
@@ -483,11 +483,13 @@ class TemplateMap {
 
   populateCollectionsWithContent() {
     for (let collectionName in this.collectionsData) {
+      // skip custom collections set in configuration files that have arbitrary types
       if (!Array.isArray(this.collectionsData[collectionName])) {
         continue;
       }
 
       for (let item of this.collectionsData[collectionName]) {
+        // skip custom collections set in configuration files that have arbitrary types
         if (!isPlainObject(item) || !("inputPath" in item)) {
           continue;
         }


Test patch:
diff --git a/test/PaginationTest.js b/test/PaginationTest.js
index 1b714197..f0e807cb 100644
--- a/test/PaginationTest.js
+++ b/test/PaginationTest.js
@@ -77,27 +77,18 @@ test("Paginate data in frontmatter", async t => {
   );
 
   let data = await tmpl.getData();
-  let paging = new Pagination(data);
-  paging.setTemplate(tmpl);
-  t.is(paging.getPageCount(), 2);
-  let pages = await paging.getPageTemplates();
+  let pages = await tmpl.getTemplates(data);
   t.is(pages.length, 2);
 
+  t.is(pages[0].outputPath, "./dist/paged/pagedinlinedata/index.html");
   t.is(
-    await pages[0].getOutputPath(),
-    "./dist/paged/pagedinlinedata/index.html"
-  );
-  t.is(
-    (await pages[0].render()).trim(),
+    (await pages[0].template.render(pages[0].data)).trim(),
     "<ol><li>item1</li><li>item2</li><li>item3</li><li>item4</li></ol>"
   );
 
+  t.is(pages[1].outputPath, "./dist/paged/pagedinlinedata/1/index.html");
   t.is(
-    await pages[1].getOutputPath(),
-    "./dist/paged/pagedinlinedata/1/index.html"
-  );
-  t.is(
-    (await pages[1].render()).trim(),
+    (await pages[1].template.render(pages[1].data)).trim(),
     "<ol><li>item5</li><li>item6</li><li>item7</li><li>item8</li></ol>"
   );
 });
@@ -118,21 +109,18 @@ test("Paginate external data file", async t => {
   // local data
   t.truthy(data.items.sub.length);
 
-  let paging = new Pagination(data);
-  paging.setTemplate(tmpl);
-  t.is(paging.getPageCount(), 2);
-  let pages = await paging.getPageTemplates();
+  let pages = await tmpl.getTemplates(data);
   t.is(pages.length, 2);
 
-  t.is(await pages[0].getOutputPath(), "./dist/paged/index.html");
+  t.is(pages[0].outputPath, "./dist/paged/index.html");
   t.is(
-    (await pages[0].render()).trim(),
+    (await pages[0].template.render(pages[0].data)).trim(),
     "<ol><li>item1</li><li>item2</li><li>item3</li><li>item4</li><li>item5</li></ol>"
   );
 
-  t.is(await pages[1].getOutputPath(), "./dist/paged/1/index.html");
+  t.is(pages[1].outputPath, "./dist/paged/1/index.html");
   t.is(
-    (await pages[1].render()).trim(),
+    (await pages[1].template.render(pages[1].data)).trim(),
     "<ol><li>item6</li><li>item7</li><li>item8</li></ol>"
   );
 });
@@ -152,19 +140,10 @@ test("Permalink with pagination variables", async t => {
   );
 
   let data = await tmpl.getData();
-  let paging = new Pagination(data);
-  paging.setTemplate(tmpl);
-  t.is(paging.getPageCount(), 2);
-  let pages = await paging.getPageTemplates();
+  let pages = await tmpl.getTemplates(data);
 
-  t.is(
-    await pages[0].getOutputPath(),
-    "./dist/paged/slug-candidate/index.html"
-  );
-  t.is(
-    await pages[1].getOutputPath(),
-    "./dist/paged/another-slug-candidate/index.html"
-  );
+  t.is(pages[0].outputPath, "./dist/paged/slug-candidate/index.html");
+  t.is(pages[1].outputPath, "./dist/paged/another-slug-candidate/index.html");
 });
 
 test("Permalink with pagination variables (numeric)", async t => {
@@ -175,32 +154,27 @@ test("Permalink with pagination variables (numeric)", async t => {
   );
 
   let data = await tmpl.getData();
-  let paging = new Pagination(data);
-  paging.setTemplate(tmpl);
-  t.is(paging.getPageCount(), 2);
-  let pages = await paging.getPageTemplates();
-
-  let page0Data = await pages[0].getData();
-  t.truthy(page0Data.pagination.firstPageLink);
-  t.truthy(page0Data.pagination.firstPageHref);
-  t.truthy(page0Data.pagination.lastPageLink);
-  t.truthy(page0Data.pagination.lastPageHref);
-  t.is(await pages[0].getOutputPath(), "./dist/paged/page-0/index.html");
-  t.falsy(page0Data.pagination.previousPageLink);
-  t.is(page0Data.pagination.nextPageLink, "/paged/page-1/index.html");
-  t.is(page0Data.pagination.nextPageHref, "/paged/page-1/");
-  t.is(page0Data.pagination.pageLinks.length, 2);
-  t.is(page0Data.pagination.links.length, 2);
-  t.is(page0Data.pagination.hrefs.length, 2);
-
-  let page1Data = await pages[1].getData();
-  t.is(await pages[1].getOutputPath(), "./dist/paged/page-1/index.html");
-  t.is(page1Data.pagination.previousPageLink, "/paged/page-0/index.html");
-  t.is(page1Data.pagination.previousPageHref, "/paged/page-0/");
-  t.falsy(page1Data.pagination.nextPageLink);
-  t.is(page1Data.pagination.pageLinks.length, 2);
-  t.is(page1Data.pagination.links.length, 2);
-  t.is(page1Data.pagination.hrefs.length, 2);
+  let pages = await tmpl.getTemplates(data);
+
+  t.truthy(pages[0].data.pagination.firstPageLink);
+  t.truthy(pages[0].data.pagination.firstPageHref);
+  t.truthy(pages[0].data.pagination.lastPageLink);
+  t.truthy(pages[0].data.pagination.lastPageHref);
+  t.is(pages[0].outputPath, "./dist/paged/page-0/index.html");
+  t.falsy(pages[0].data.pagination.previousPageLink);
+  t.is(pages[0].data.pagination.nextPageLink, "/paged/page-1/index.html");
+  t.is(pages[0].data.pagination.nextPageHref, "/paged/page-1/");
+  t.is(pages[0].data.pagination.pageLinks.length, 2);
+  t.is(pages[0].data.pagination.links.length, 2);
+  t.is(pages[0].data.pagination.hrefs.length, 2);
+
+  t.is(pages[1].outputPath, "./dist/paged/page-1/index.html");
+  t.is(pages[1].data.pagination.previousPageLink, "/paged/page-0/index.html");
+  t.is(pages[1].data.pagination.previousPageHref, "/paged/page-0/");
+  t.falsy(pages[1].data.pagination.nextPageLink);
+  t.is(pages[1].data.pagination.pageLinks.length, 2);
+  t.is(pages[1].data.pagination.links.length, 2);
+  t.is(pages[1].data.pagination.hrefs.length, 2);
 });
 
 test("Permalink with pagination variables (numeric, one indexed)", async t => {
@@ -211,27 +185,23 @@ test("Permalink with pagination variables (numeric, one indexed)", async t => {
   );
 
   let data = await tmpl.getData();
-  let paging = new Pagination(data);
-  paging.setTemplate(tmpl);
-  let pages = await paging.getPageTemplates();
-
-  let page0Data = await pages[0].getData();
-  t.is(await pages[0].getOutputPath(), "./dist/paged/page-1/index.html");
-  t.falsy(page0Data.pagination.previousPageLink);
-  t.is(page0Data.pagination.nextPageLink, "/paged/page-2/index.html");
-  t.is(page0Data.pagination.nextPageHref, "/paged/page-2/");
-  t.is(page0Data.pagination.pageLinks.length, 2);
-  t.is(page0Data.pagination.links.length, 2);
-  t.is(page0Data.pagination.hrefs.length, 2);
-
-  let page1Data = await pages[1].getData();
-  t.is(await pages[1].getOutputPath(), "./dist/paged/page-2/index.html");
-  t.is(page1Data.pagination.previousPageLink, "/paged/page-1/index.html");
-  t.is(page1Data.pagination.previousPageHref, "/paged/page-1/");
-  t.falsy(page1Data.pagination.nextPageLink);
-  t.is(page1Data.pagination.pageLinks.length, 2);
-  t.is(page1Data.pagination.links.length, 2);
-  t.is(page1Data.pagination.hrefs.length, 2);
+  let pages = await tmpl.getTemplates(data);
+
+  t.is(pages[0].outputPath, "./dist/paged/page-1/index.html");
+  t.falsy(pages[0].data.pagination.previousPageLink);
+  t.is(pages[0].data.pagination.nextPageLink, "/paged/page-2/index.html");
+  t.is(pages[0].data.pagination.nextPageHref, "/paged/page-2/");
+  t.is(pages[0].data.pagination.pageLinks.length, 2);
+  t.is(pages[0].data.pagination.links.length, 2);
+  t.is(pages[0].data.pagination.hrefs.length, 2);
+
+  t.is(pages[1].outputPath, "./dist/paged/page-2/index.html");
+  t.is(pages[1].data.pagination.previousPageLink, "/paged/page-1/index.html");
+  t.is(pages[1].data.pagination.previousPageHref, "/paged/page-1/");
+  t.falsy(pages[1].data.pagination.nextPageLink);
+  t.is(pages[1].data.pagination.pageLinks.length, 2);
+  t.is(pages[1].data.pagination.links.length, 2);
+  t.is(pages[1].data.pagination.hrefs.length, 2);
 });
 
 test("Permalink first and last page link with pagination variables (numeric)", async t => {
@@ -242,17 +212,13 @@ test("Permalink first and last page link with pagination variables (numeric)", a
   );
 
   let data = await tmpl.getData();
-  let paging = new Pagination(data);
-  paging.setTemplate(tmpl);
-  let pages = await paging.getPageTemplates();
+  let pages = await tmpl.getTemplates(data);
 
-  let page0Data = await pages[0].getData();
-  t.is(page0Data.pagination.firstPageLink, "/paged/page-0/index.html");
-  t.is(page0Data.pagination.lastPageLink, "/paged/page-1/index.html");
+  t.is(pages[0].data.pagination.firstPageLink, "/paged/page-0/index.html");
+  t.is(pages[0].data.pagination.lastPageLink, "/paged/page-1/index.html");
 
-  let page1Data = await pages[1].getData();
-  t.is(page1Data.pagination.firstPageLink, "/paged/page-0/index.html");
-  t.is(page1Data.pagination.lastPageLink, "/paged/page-1/index.html");
+  t.is(pages[1].data.pagination.firstPageLink, "/paged/page-0/index.html");
+  t.is(pages[1].data.pagination.lastPageLink, "/paged/page-1/index.html");
 });
 
 test("Permalink first and last page link with pagination variables (numeric, one indexed)", async t => {
@@ -263,17 +229,13 @@ test("Permalink first and last page link with pagination variables (numeric, one
   );
 
   let data = await tmpl.getData();
-  let paging = new Pagination(data);
-  paging.setTemplate(tmpl);
-  let pages = await paging.getPageTemplates();
+  let pages = await tmpl.getTemplates(data);
 
-  let page0Data = await pages[0].getData();
-  t.is(page0Data.pagination.firstPageLink, "/paged/page-1/index.html");
-  t.is(page0Data.pagination.lastPageLink, "/paged/page-2/index.html");
+  t.is(pages[0].data.pagination.firstPageLink, "/paged/page-1/index.html");
+  t.is(pages[0].data.pagination.lastPageLink, "/paged/page-2/index.html");
 
-  let page1Data = await pages[1].getData();
-  t.is(page0Data.pagination.firstPageLink, "/paged/page-1/index.html");
-  t.is(page0Data.pagination.lastPageLink, "/paged/page-2/index.html");
+  t.is(pages[1].data.pagination.firstPageLink, "/paged/page-1/index.html");
+  t.is(pages[1].data.pagination.lastPageLink, "/paged/page-2/index.html");
 });
 
 test("Alias to page data", async t => {
@@ -284,15 +246,13 @@ test("Alias to page data", async t => {
   );
 
   let data = await tmpl.getData();
-  let paging = new Pagination(data);
-  paging.setTemplate(tmpl);
-  let pages = await paging.getPageTemplates();
+  let pages = await tmpl.getTemplates(data);
 
-  t.is(await pages[0].getOutputPath(), "./dist/pagedalias/item1/index.html");
-  t.is(await pages[1].getOutputPath(), "./dist/pagedalias/item2/index.html");
+  t.is(pages[0].outputPath, "./dist/pagedalias/item1/index.html");
+  t.is(pages[1].outputPath, "./dist/pagedalias/item2/index.html");
 
-  t.is((await pages[0].render()).trim(), "item1");
-  t.is((await pages[1].render()).trim(), "item2");
+  t.is((await pages[0].template.render(pages[0].data)).trim(), "item1");
+  t.is((await pages[1].template.render(pages[1].data)).trim(), "item2");
 });
 
 test("Alias to page data (size 2)", async t => {
@@ -303,15 +263,13 @@ test("Alias to page data (size 2)", async t => {
   );
 
   let data = await tmpl.getData();
-  let paging = new Pagination(data);
-  paging.setTemplate(tmpl);
-  let pages = await paging.getPageTemplates();
+  let pages = await tmpl.getTemplates(data);
 
-  t.is(await pages[0].getOutputPath(), "./dist/pagedalias/item1/index.html");
-  t.is(await pages[1].getOutputPath(), "./dist/pagedalias/item3/index.html");
+  t.is(pages[0].outputPath, "./dist/pagedalias/item1/index.html");
+  t.is(pages[1].outputPath, "./dist/pagedalias/item3/index.html");
 
-  t.is((await pages[0].render()).trim(), "item1");
-  t.is((await pages[1].render()).trim(), "item3");
+  t.is((await pages[0].template.render(pages[0].data)).trim(), "item1");
+  t.is((await pages[1].template.render(pages[1].data)).trim(), "item3");
 });
 
 test("Permalink with pagination variables (and an if statement, nunjucks)", async t => {
@@ -322,12 +280,10 @@ test("Permalink with pagination variables (and an if statement, nunjucks)", asyn
   );
 
   let data = await tmpl.getData();
-  let paging = new Pagination(data);
-  paging.setTemplate(tmpl);
-  let pages = await paging.getPageTemplates();
+  let pages = await tmpl.getTemplates(data);
 
-  t.is(await pages[0].getOutputPath(), "./dist/paged/index.html");
-  t.is(await pages[1].getOutputPath(), "./dist/paged/page-1/index.html");
+  t.is(pages[0].outputPath, "./dist/paged/index.html");
+  t.is(pages[1].outputPath, "./dist/paged/page-1/index.html");
 });
 
 test("Permalink with pagination variables (and an if statement, liquid)", async t => {
@@ -338,12 +294,10 @@ test("Permalink with pagination variables (and an if statement, liquid)", async
   );
 
   let data = await tmpl.getData();
-  let paging = new Pagination(data);
-  paging.setTemplate(tmpl);
-  let pages = await paging.getPageTemplates();
+  let pages = await tmpl.getTemplates(data);
 
-  t.is(await pages[0].getOutputPath(), "./dist/paged/index.html");
-  t.is(await pages[1].getOutputPath(), "./dist/paged/page-1/index.html");
+  t.is(pages[0].outputPath, "./dist/paged/index.html");
+  t.is(pages[1].outputPath, "./dist/paged/page-1/index.html");
 });
 
 test("Template with Pagination, getRenderedTemplates", async t => {
@@ -381,14 +335,9 @@ test("Issue 135", async t => {
     "./dist/blog/do-you-even-paginate-bro/index.html"
   );
 
-  let paging = new Pagination(data);
-  paging.setTemplate(tmpl);
-  let pages = await paging.getPageTemplates();
+  let pages = await tmpl.getTemplates(data);
   t.is(pages.length, 1);
-  t.is(
-    await pages[0].getOutputPath(),
-    "./dist/blog/do-you-even-paginate-bro/index.html"
-  );
+  t.is(pages[0].outputPath, "./dist/blog/do-you-even-paginate-bro/index.html");
 });
 
 test("Template with Pagination, getTemplates has page variables set", async t => {
@@ -415,12 +364,12 @@ test("Template with Pagination, getRenderedTemplates has page variables set", as
   );
 
   let data = await tmpl.getData();
-  let templates = await tmpl.getRenderedTemplates(data);
-  t.is(templates[0].data.page.url, "/paged/");
-  t.is(templates[0].data.page.outputPath, "./dist/paged/index.html");
+  let pages = await tmpl.getRenderedTemplates(data);
+  t.is(pages[0].data.page.url, "/paged/");
+  t.is(pages[0].data.page.outputPath, "./dist/paged/index.html");
 
-  t.is(templates[1].data.page.url, "/paged/page-1/");
-  t.is(templates[1].data.page.outputPath, "./dist/paged/page-1/index.html");
+  t.is(pages[1].data.page.url, "/paged/page-1/");
+  t.is(pages[1].data.page.outputPath, "./dist/paged/page-1/index.html");
 });
 
 test("Page over an object (use keys)", async t => {
@@ -431,20 +380,18 @@ test("Page over an object (use keys)", async t => {
   );
 
   let data = await tmpl.getData();
-  let paging = new Pagination(data);
-  paging.setTemplate(tmpl);
-  let pages = await paging.getPageTemplates();
+  let pages = await tmpl.getTemplates(data);
   t.is(pages.length, 3);
 
-  t.is(await pages[0].getOutputPath(), "./dist/paged/pagedobject/index.html");
+  t.is(pages[0].outputPath, "./dist/paged/pagedobject/index.html");
   t.is(
-    (await pages[0].render()).trim(),
+    (await pages[0].template.render(pages[0].data)).trim(),
     "<ol><li>item1</li><li>item2</li><li>item3</li><li>item4</li></ol>"
   );
 
-  t.is(await pages[1].getOutputPath(), "./dist/paged/pagedobject/1/index.html");
+  t.is(pages[1].outputPath, "./dist/paged/pagedobject/1/index.html");
   t.is(
-    (await pages[1].render()).trim(),
+    (await pages[1].template.render(pages[1].data)).trim(),
     "<ol><li>item5</li><li>item6</li><li>item7</li><li>item8</li></ol>"
   );
 });
@@ -457,26 +404,18 @@ test("Page over an object (use values)", async t => {
   );
 
   let data = await tmpl.getData();
-  let paging = new Pagination(data);
-  paging.setTemplate(tmpl);
-  let pages = await paging.getPageTemplates();
+  let pages = await tmpl.getTemplates(data);
   t.is(pages.length, 3);
 
+  t.is(pages[0].outputPath, "./dist/paged/pagedobjectvalues/index.html");
   t.is(
-    await pages[0].getOutputPath(),
-    "./dist/paged/pagedobjectvalues/index.html"
-  );
-  t.is(
-    (await pages[0].render()).trim(),
+    (await pages[0].template.render(pages[0].data)).trim(),
     "<ol><li>itemvalue1</li><li>itemvalue2</li><li>itemvalue3</li><li>itemvalue4</li></ol>"
   );
 
+  t.is(pages[1].outputPath, "./dist/paged/pagedobjectvalues/1/index.html");
   t.is(
-    await pages[1].getOutputPath(),
-    "./dist/paged/pagedobjectvalues/1/index.html"
-  );
-  t.is(
-    (await pages[1].render()).trim(),
+    (await pages[1].template.render(pages[1].data)).trim(),
     "<ol><li>itemvalue5</li><li>itemvalue6</li><li>itemvalue7</li><li>itemvalue8</li></ol>"
   );
 });
@@ -489,18 +428,15 @@ test("Page over an object (filtered, array)", async t => {
   );
 
   let data = await tmpl.getData();
-  let paging = new Pagination(data);
-  paging.setTemplate(tmpl);
-  let pages = await paging.getPageTemplates();
-  t.is(pages.length, 2);
+  let pages = await tmpl.getTemplates(data);
 
   t.is(
-    (await pages[0].render()).trim(),
+    (await pages[0].template.render(pages[0].data)).trim(),
     "<ol><li>item1</li><li>item2</li><li>item3</li><li>item5</li></ol>"
   );
 
   t.is(
-    (await pages[1].render()).trim(),
+    (await pages[1].template.render(pages[1].data)).trim(),
     "<ol><li>item6</li><li>item7</li><li>item8</li><li>item9</li></ol>"
   );
 });
@@ -513,18 +449,16 @@ test("Page over an object (filtered, string)", async t => {
   );
 
   let data = await tmpl.getData();
-  let paging = new Pagination(data);
-  paging.setTemplate(tmpl);
-  let pages = await paging.getPageTemplates();
+  let pages = await tmpl.getTemplates(data);
   t.is(pages.length, 2);
 
   t.is(
-    (await pages[0].render()).trim(),
+    (await pages[0].template.render(pages[0].data)).trim(),
     "<ol><li>item1</li><li>item2</li><li>item3</li><li>item5</li></ol>"
   );
 
   t.is(
-    (await pages[1].render()).trim(),
+    (await pages[1].template.render(pages[1].data)).trim(),
     "<ol><li>item6</li><li>item7</li><li>item8</li><li>item9</li></ol>"
   );
 });
@@ -543,26 +477,18 @@ test("Pagination with deep data merge #147", async t => {
   };
 
   let data = await tmpl.getData();
-  let paging = new Pagination(data);
-  paging.setTemplate(tmpl);
-  let pages = await paging.getPageTemplates();
+  let pages = await tmpl.getTemplates(data);
   t.is(pages.length, 2);
 
+  t.is(pages[0].outputPath, "./dist/paged/pagedinlinedata/index.html");
   t.is(
-    await pages[0].getOutputPath(),
-    "./dist/paged/pagedinlinedata/index.html"
-  );
-  t.is(
-    (await pages[0].render()).trim(),
+    (await pages[0].template.render(pages[0].data)).trim(),
     "<ol><li>item1</li><li>item2</li><li>item3</li><li>item4</li></ol>"
   );
 
+  t.is(pages[1].outputPath, "./dist/paged/pagedinlinedata/1/index.html");
   t.is(
-    await pages[1].getOutputPath(),
-    "./dist/paged/pagedinlinedata/1/index.html"
-  );
-  t.is(
-    (await pages[1].render()).trim(),
+    (await pages[1].template.render(pages[1].data)).trim(),
     "<ol><li>item5</li><li>item6</li><li>item7</li><li>item8</li></ol>"
   );
 });
@@ -583,14 +509,13 @@ test("Pagination with deep data merge with alias #147", async t => {
   };
 
   let data = await tmpl.getData();
-  let paging = new Pagination(data);
-  paging.setTemplate(tmpl);
-  let pages = await paging.getPageTemplates();
-  t.is(await pages[0].getOutputPath(), "./dist/pagedalias/item1/index.html");
-  t.is(await pages[1].getOutputPath(), "./dist/pagedalias/item2/index.html");
+  let pages = await tmpl.getTemplates(data);
+
+  t.is(pages[0].outputPath, "./dist/pagedalias/item1/index.html");
+  t.is(pages[1].outputPath, "./dist/pagedalias/item2/index.html");
 
-  t.is((await pages[0].render()).trim(), "item1");
-  t.is((await pages[1].render()).trim(), "item2");
+  t.is((await pages[0].template.render(pages[0].data)).trim(), "item1");
+  t.is((await pages[1].template.render(pages[1].data)).trim(), "item2");
 });
 
 test("Paginate data in frontmatter (reversed)", async t => {
@@ -601,26 +526,21 @@ test("Paginate data in frontmatter (reversed)", async t => {
   );
 
   let data = await tmpl.getData();
-  let paging = new Pagination(data);
-  paging.setTemplate(tmpl);
-  let pages = await paging.getPageTemplates();
+  let pages = await tmpl.getTemplates(data);
   t.is(pages.length, 2);
 
+  t.is(pages[0].outputPath, "./dist/paged/pagedinlinedata-reverse/index.html");
   t.is(
-    await pages[0].getOutputPath(),
-    "./dist/paged/pagedinlinedata-reverse/index.html"
-  );
-  t.is(
-    (await pages[0].render()).trim(),
+    (await pages[0].template.render(pages[0].data)).trim(),
     "<ol><li>item8</li><li>item7</li><li>item6</li><li>item5</li></ol>"
   );
 
   t.is(
-    await pages[1].getOutputPath(),
+    pages[1].outputPath,
     "./dist/paged/pagedinlinedata-reverse/1/index.html"
   );
   t.is(
-    (await pages[1].render()).trim(),
+    (await pages[1].template.render(pages[1].data)).trim(),
     "<ol><li>item4</li><li>item3</li><li>item2</li><li>item1</li></ol>"
   );
 });
diff --git a/test/TemplateMapTest.js b/test/TemplateMapTest.js
index b566bfed..80c04521 100644
--- a/test/TemplateMapTest.js
+++ b/test/TemplateMapTest.js
@@ -779,7 +779,7 @@ test("Template pages should not have layouts when added to collections", async t
     "./test/stubs/_site"
   );
   await tm.add(tmpl);
-  t.is(await tmpl.render(), "<div>Layout Test</div>");
+  t.is(await tmpl.render(await tmpl.getData()), "<div>Layout Test</div>");
 
   let collections = await tm._testGetCollectionsData();
   t.is(collections.all.length, 1);
diff --git a/test/TemplateRenderJavaScriptTest.js b/test/TemplateRenderJavaScriptTest.js
index 02462002..9f29cd9f 100644
--- a/test/TemplateRenderJavaScriptTest.js
+++ b/test/TemplateRenderJavaScriptTest.js
@@ -181,8 +181,8 @@ test("JS Render with a function", async t => {
   t.is(await fn({ name: "Bill" }), "<p>BILLT9000</p>");
 });
 
-// This doesn’t work
-test.skip("JS Render with an arrow function and javascript function", async t => {
+// This doesn’t work, per arrow functions
+test.skip("Issue #934: JS Render with an arrow function and javascript function", async t => {
   let tr = new TemplateRender("./test/stubs/function-filter-arrow.11ty.js");
   tr.config = {
     javascriptFunctions: {
diff --git a/test/TemplateTest-JavaScript.js b/test/TemplateTest-JavaScript.js
index 5fabb828..621b8a8f 100644
--- a/test/TemplateTest-JavaScript.js
+++ b/test/TemplateTest-JavaScript.js
@@ -199,7 +199,7 @@ test("JavaScript template type (class with renderData)", async t => {
     "./dist"
   );
 
-  let data = await tmpl.getRenderedData();
+  let data = await tmpl.getData();
   let pages = await tmpl.getRenderedTemplates(data);
   t.is(
     pages[0].templateContent.trim(),
diff --git a/test/TemplateTest.js b/test/TemplateTest.js
index 74811a91..df369969 100644
--- a/test/TemplateTest.js
+++ b/test/TemplateTest.js
@@ -10,6 +10,12 @@ import normalizeNewLines from "./Util/normalizeNewLines";
 
 const config = templateConfig.getConfig();
 
+async function getRenderedData(tmpl, pageNumber = 0) {
+  let data = await tmpl.getData();
+  let templates = await tmpl.getTemplates(data);
+  return templates[pageNumber].data;
+}
+
 function cleanHtml(str) {
   return pretty(str, { ocd: true });
 }
@@ -334,7 +340,7 @@ test("Liquid template", async t => {
     dataObj
   );
 
-  t.is(await tmpl.render(), `<p>Zach</p>`);
+  t.is(await tmpl.render(await tmpl.getData()), `<p>Zach</p>`);
 });
 
 test("Liquid template with include", async t => {
@@ -344,7 +350,10 @@ test("Liquid template with include", async t => {
     "dist"
   );
 
-  t.is((await tmpl.render()).trim(), "<p>This is an include.</p>");
+  t.is(
+    (await tmpl.render(await tmpl.getData())).trim(),
+    "<p>This is an include.</p>"
+  );
 });
 
 test("ES6 Template Literal (No Backticks)", async t => {
@@ -356,7 +365,7 @@ test("ES6 Template Literal (No Backticks)", async t => {
     dataObj
   );
 
-  t.is((await tmpl.render()).trim(), `<p>ZACH</p>`);
+  t.is((await tmpl.render(await tmpl.getData())).trim(), `<p>ZACH</p>`);
 });
 
 test("ES6 Template Literal (with Backticks)", async t => {
@@ -368,7 +377,7 @@ test("ES6 Template Literal (with Backticks)", async t => {
     dataObj
   );
 
-  t.is((await tmpl.render()).trim(), `<p>ZACH</p>`);
+  t.is((await tmpl.render(await tmpl.getData())).trim(), `<p>ZACH</p>`);
 });
 
 test("Permalink output directory", async t => {
@@ -449,7 +458,7 @@ test("Local template data file import (without a global data json)", async t =>
     "./test/stubs/component/component.11tydata.js"
   ]);
   t.is(data.localdatakey1, "localdatavalue1");
-  t.is(await tmpl.render(), "localdatavalue1");
+  t.is(await tmpl.render(data), "localdatavalue1");
 });
 
 test("Local template data file import (two subdirectories deep)", async t => {
@@ -665,8 +674,8 @@ test("renderData", async t => {
     "./test/stubs/",
     "./dist"
   );
-
-  t.is((await tmpl.render()).trim(), "hi:value2-value1.css");
+  let data = await getRenderedData(tmpl);
+  t.is((await tmpl.render(data)).trim(), "hi:value2-value1.css");
 });
 
 test("renderData markdown (issue #40)", async t => {
@@ -675,8 +684,8 @@ test("renderData markdown (issue #40)", async t => {
     "./test/stubs/",
     "./dist"
   );
-
-  t.is((await tmpl.render()).trim(), "<title>value2-value1.css</title>");
+  let data = await getRenderedData(tmpl);
+  t.is((await tmpl.render(data)).trim(), "<title>value2-value1.css</title>");
 });
 
 test("getMappedDate (empty, assume created)", async t => {
@@ -685,7 +694,7 @@ test("getMappedDate (empty, assume created)", async t => {
     "./test/stubs/",
     "./dist"
   );
-  let data = await tmpl.getRenderedData();
+  let data = await getRenderedData(tmpl);
   let date = await tmpl.getMappedDate(data);
 
   t.true(date instanceof Date);
@@ -698,7 +707,7 @@ test("getMappedDate (explicit date, yaml String)", async t => {
     "./test/stubs/",
     "./dist"
   );
-  let data = await tmpl.getRenderedData();
+  let data = await getRenderedData(tmpl);
   let date = await tmpl.getMappedDate(data);
 
   t.true(date instanceof Date);
@@ -711,7 +720,7 @@ test("getMappedDate (explicit date, yaml Date)", async t => {
     "./test/stubs/",
     "./dist"
   );
-  let data = await tmpl.getRenderedData();
+  let data = await getRenderedData(tmpl);
   let date = await tmpl.getMappedDate(data);
 
   t.true(date instanceof Date);
@@ -724,7 +733,7 @@ test("getMappedDate (explicit date, yaml Date and string should be the same)", a
     "./test/stubs/",
     "./dist"
   );
-  let dataA = await tmplA.getRenderedData();
+  let dataA = await getRenderedData(tmplA);
   let stringDate = await tmplA.getMappedDate(dataA);
 
   let tmplB = new Template(
@@ -732,7 +741,7 @@ test("getMappedDate (explicit date, yaml Date and string should be the same)", a
     "./test/stubs/",
     "./dist"
   );
-  let dataB = await tmplB.getRenderedData();
+  let dataB = await getRenderedData(tmplB);
   let yamlDate = await tmplB.getMappedDate(dataB);
 
   t.truthy(stringDate);
@@ -746,7 +755,7 @@ test("getMappedDate (modified date)", async t => {
     "./test/stubs/",
     "./dist"
   );
-  let data = await tmpl.getRenderedData();
+  let data = await getRenderedData(tmpl);
   let date = await tmpl.getMappedDate(data);
 
   t.true(date instanceof Date);
@@ -759,7 +768,7 @@ test("getMappedDate (created date)", async t => {
     "./test/stubs/",
     "./dist"
   );
-  let data = await tmpl.getRenderedData();
+  let data = await getRenderedData(tmpl);
   let date = await tmpl.getMappedDate(data);
 
   t.true(date instanceof Date);
@@ -772,7 +781,7 @@ test("getMappedDate (falls back to filename date)", async t => {
     "./test/stubs/",
     "./dist"
   );
-  let data = await tmpl.getRenderedData();
+  let data = await getRenderedData(tmpl);
   let date = await tmpl.getMappedDate(data);
 
   t.true(date instanceof Date);
@@ -785,7 +794,7 @@ test("getRenderedData() has all the page variables", async t => {
     "./test/stubs/",
     "./dist"
   );
-  let data = await tmpl.getRenderedData();
+  let data = await getRenderedData(tmpl);
 
   t.truthy(data.page.url);
   t.is(data.page.url, "/template/");
@@ -895,7 +904,7 @@ test("getRenderedTemplates() data has all the page variables", async t => {
 
 test("getRenderedData() has good slug (empty, index)", async t => {
   let tmpl = new Template("./test/stubs/index.ejs", "./test/stubs/", "./dist");
-  let data = await tmpl.getRenderedData();
+  let data = await getRenderedData(tmpl);
   t.is(data.page.fileSlug, "");
   t.is(data.page.filePathStem, "/index");
 });
@@ -906,7 +915,7 @@ test("getRenderedData() has good slug", async t => {
     "./test/stubs/",
     "./dist"
   );
-  let data = await tmpl.getRenderedData();
+  let data = await getRenderedData(tmpl);
   t.is(data.page.fileSlug, "includer");
   t.is(data.page.filePathStem, "/includer");
 });
@@ -918,7 +927,7 @@ test("Override base templating engine from .liquid to ejs", async t => {
     "./dist"
   );
 
-  t.is((await tmpl.render()).trim(), "My Title");
+  t.is((await tmpl.render(await tmpl.getData())).trim(), "My Title");
 });
 
 test("Override base templating engine from markdown to 11ty.js, then markdown", async t => {
@@ -928,7 +937,10 @@ test("Override base templating engine from markdown to 11ty.js, then markdown",
     "./dist"
   );
 
-  t.is((await tmpl.render()).trim(), "<h1>This is markdown</h1>");
+  t.is(
+    (await tmpl.render(await tmpl.getData())).trim(),
+    "<h1>This is markdown</h1>"
+  );
 });
 
 test("Override base templating engine from .liquid to md", async t => {
@@ -938,7 +950,7 @@ test("Override base templating engine from .liquid to md", async t => {
     "./dist"
   );
 
-  t.is((await tmpl.render()).trim(), "<h1>My Title</h1>");
+  t.is((await tmpl.render(await tmpl.getData())).trim(), "<h1>My Title</h1>");
 });
 
 test("Override base templating engine from .liquid to ejs,md", async t => {
@@ -948,7 +960,7 @@ test("Override base templating engine from .liquid to ejs,md", async t => {
     "./dist"
   );
 
-  t.is((await tmpl.render()).trim(), "<h1>My Title</h1>");
+  t.is((await tmpl.render(await tmpl.getData())).trim(), "<h1>My Title</h1>");
 });
 
 test("Override base templating engine from .njk to ejs,md", async t => {
@@ -958,7 +970,7 @@ test("Override base templating engine from .njk to ejs,md", async t => {
     "./dist"
   );
 
-  t.is((await tmpl.render()).trim(), "<h1>My Title</h1>");
+  t.is((await tmpl.render(await tmpl.getData())).trim(), "<h1>My Title</h1>");
 });
 
 test("Override base templating engine from .html to ejs", async t => {
@@ -968,7 +980,7 @@ test("Override base templating engine from .html to ejs", async t => {
     "./dist"
   );
 
-  t.is((await tmpl.render()).trim(), "<h2>My Title</h2>");
+  t.is((await tmpl.render(await tmpl.getData())).trim(), "<h2>My Title</h2>");
 });
 
 test("Override base templating engine from .html to (nothing)", async t => {
@@ -978,7 +990,10 @@ test("Override base templating engine from .html to (nothing)", async t => {
     "./dist"
   );
 
-  t.is((await tmpl.render()).trim(), "<h2><%= title %></h2>");
+  t.is(
+    (await tmpl.render(await tmpl.getData())).trim(),
+    "<h2><%= title %></h2>"
+  );
 });
 
 test("Override base templating engine should error with bad string", async t => {
@@ -989,7 +1004,7 @@ test("Override base templating engine should error with bad string", async t =>
   );
 
   await t.throwsAsync(async () => {
-    await tmpl.render();
+    await tmpl.render(await tmpl.getData());
   });
 });
 
@@ -1000,7 +1015,7 @@ test("Override base templating engine (bypasses markdown)", async t => {
     "./dist"
   );
 
-  t.is((await tmpl.render()).trim(), "# My Title");
+  t.is((await tmpl.render(await tmpl.getData())).trim(), "# My Title");
 });
 
 test("Override base templating engine to (nothing)", async t => {
@@ -1011,7 +1026,7 @@ test("Override base templating engine to (nothing)", async t => {
   );
 
   // not parsed
-  t.is((await tmpl.render()).trim(), "# <%= title %>");
+  t.is((await tmpl.render(await tmpl.getData())).trim(), "# <%= title %>");
 });
 
 test("Override base templating engine from .ejs to njk", async t => {
@@ -1021,7 +1036,7 @@ test("Override base templating engine from .ejs to njk", async t => {
     "./dist"
   );
 
-  t.is((await tmpl.render()).trim(), "My Title");
+  t.is((await tmpl.render(await tmpl.getData())).trim(), "My Title");
 });
 
 test("Override base templating engine from .njk to ejs (with a layout that uses njk)", async t => {
@@ -1032,7 +1047,7 @@ test("Override base templating engine from .njk to ejs (with a layout that uses
   );
 
   t.is(
-    (await tmpl.render()).trim(),
+    (await tmpl.render(await tmpl.getData())).trim(),
     '<div id="layoutvalue"><h2>My Title</h2></div>'
   );
 });
@@ -1045,7 +1060,7 @@ test("Override base templating engine from .njk to nothing (with a layout that u
   );
 
   t.is(
-    (await tmpl.render()).trim(),
+    (await tmpl.render(await tmpl.getData())).trim(),
     `<div id="layoutvalue"><h2><%= title %></h2></div>`
   );
 });
@@ -1058,7 +1073,7 @@ test("Using a markdown source file (with a layout that uses njk), markdown shoul
   );
 
   t.is(
-    normalizeNewLines((await tmpl.render()).trim()),
+    normalizeNewLines((await tmpl.render(await tmpl.getData())).trim()),
     `# Layout header
 
 <div id="layoutvalue"><h1>My Title</h1>
@@ -1074,7 +1089,7 @@ test("Override base templating engine from .md to ejs,md (with a layout that use
   );
 
   t.is(
-    normalizeNewLines((await tmpl.render()).trim()),
+    normalizeNewLines((await tmpl.render(await tmpl.getData())).trim()),
     `# Layout header
 
 <div id="layoutvalue"><h1>My Title</h1>
@@ -1959,7 +1974,9 @@ test("Issue #446: Layout has a permalink with a different template language than
 
 // Prior to and including 0.10.0 this mismatched the documentation)!
 test("Layout front matter should override template files", async t => {
-  let dataObj = new TemplateData("./test/stubs-data-cascade/layout-data-files/");
+  let dataObj = new TemplateData(
+    "./test/stubs-data-cascade/layout-data-files/"
+  );
   let tmpl = new Template(
     "./test/stubs-data-cascade/layout-data-files/test.njk",
     "./test/stubs-data-cascade/layout-data-files/",
@@ -1979,5 +1996,8 @@ test("Get Layout Chain", async t => {
   );
 
   let layoutChain = await tmpl.getLayoutChain();
-  t.deepEqual(layoutChain, ["./test/stubs-incremental/layout-chain/_includes/base.njk", "./test/stubs-incremental/layout-chain/_includes/parent.njk"]);
+  t.deepEqual(layoutChain, [
+    "./test/stubs-incremental/layout-chain/_includes/base.njk",
+    "./test/stubs-incremental/layout-chain/_includes/parent.njk"
+  ]);
 });
diff --git a/test/TemplateWriterTest.js b/test/TemplateWriterTest.js
index 0b106fa4..bed25b6f 100644
--- a/test/TemplateWriterTest.js
+++ b/test/TemplateWriterTest.js
@@ -474,8 +474,7 @@ test("fileSlug should exist in a collection", async t => {
   t.is(templates[0].templateContent.trim(), "fileSlug:/dog1/:dog1");
 });
 
-// TODO
-test.skip("renderData should exist and be resolved in a collection (Issue #289)", async t => {
+test("renderData should exist and be resolved in a collection (Issue #289)", async t => {
   let tw = new TemplateWriter(
     "./test/stubs/collection-renderdata",
     "./test/stubs/collection-renderdata/_site",
@@ -495,7 +494,7 @@ test.skip("renderData should exist and be resolved in a collection (Issue #289)"
   t.is(mapEntry.inputPath, "./test/stubs/collection-renderdata/template.njk");
 
   let templates = await mapEntry.template.getRenderedTemplates(mapEntry.data);
-  t.is(templates[0].templateContent.trim(), "Test Title");
+  t.is(templates[0].templateContent.trim(), "value2-value1.css");
 });
 
 test("Write Test 11ty.js", async t => {