From d2a09d141f9d8ed3006d528d09858aac64b1f4e1 Mon Sep 17 00:00:00 2001
From: Dave DeSandro <desandrocodes@gmail.com>
Date: Thu, 31 Dec 2020 07:09:57 -0500
Subject: [PATCH] =?UTF-8?q?=F0=9F=94=94=20#840=20trigger=20last=20if=200?=
 =?UTF-8?q?=20items=20appended?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

✅ fix checkLastPage with falsey function
---
 js/page-load.js           | 13 ++++++++---
 test/check-last-page.js   | 49 ++++++++++++++++++++++++++++-----------
 test/html/page/empty.html | 15 ++++++++++++
 test/outlayer.js          | 19 ++++++---------
 4 files changed, 68 insertions(+), 28 deletions(-)
 create mode 100644 test/html/page/empty.html

diff --git a/js/page-load.js b/js/page-load.js
index 7b8d3dc..b101942 100644
--- a/js/page-load.js
+++ b/js/page-load.js
@@ -91,18 +91,25 @@ proto.onPageLoad = function( body, path, response ) {
 };
 
 proto.appendNextPage = function( body, path, response ) {
-  let { append, responseBody } = this.options;
+  let { append, responseBody, domParseResponse } = this.options;
   // do not append json
-  let isDocument = responseBody == 'text';
+  let isDocument = responseBody == 'text' && domParseResponse;
   if ( !isDocument || !append ) return { body, response };
 
   let items = body.querySelectorAll( append );
+  let promiseValue = { body, response, items };
+  // last page hit if no items. #840
+  if ( !items || !items.length ) {
+    this.lastPageReached( body, path );
+    return promiseValue;
+  }
+
   let fragment = getItemsFragment( items );
   let appendReady = () => {
     this.appendItems( items, fragment );
     this.isLoading = false;
     this.dispatchEvent( 'append', null, [ body, path, items ] );
-    return { body, response, items };
+    return promiseValue;
   };
 
   // TODO add hook for option to trigger appendReady
diff --git a/test/check-last-page.js b/test/check-last-page.js
index fa05520..9b5f1f2 100644
--- a/test/check-last-page.js
+++ b/test/check-last-page.js
@@ -36,17 +36,9 @@ function getPageAssertions() {
       serialT.fail('last event should not trigger when not last page');
     }
 
-    await ( function() {
-      let promise = new Promise( function( resolve ) {
-        infScroll.once( 'append', function() {
-          infScroll.off( 'last', onLast );
-          resolve();
-        } );
-      } );
-      // load page 2
-      infScroll.loadNextPage();
-      return promise;
-    } )();
+    await infScroll.loadNextPage().then( function() {
+      infScroll.off( 'last', onLast );
+    } );
 
     let promise = new Promise( function( resolve ) {
       infScroll.once( 'last', function() {
@@ -88,13 +80,15 @@ test( 'checkLastPage: ".selector-string"', withPage, async function( t, page ) {
   assertions.forEach( ({ method, args }) => t[ method ]( ...args ) );
 } );
 
-test( 'checkLastPage with path: function() {}', withPage, async function( t, page ) {
+test( 'checkLastPage with empty page', withPage, async function( t, page ) {
   await page.evaluate( function() {
     window.infScroll = new InfiniteScroll( '.container', {
       // provide only page/2.html, then falsy
       path: function() {
-        if ( this.pageIndex < 3 ) {
+        if ( this.pageIndex < 2 ) {
           return `page/${this.pageIndex + 1}.html`;
+        } else {
+          return 'page/empty.html';
         }
       },
       // checkLastPage: true, // true by default
@@ -105,3 +99,32 @@ test( 'checkLastPage with path: function() {}', withPage, async function( t, pag
   let assertions = await page.evaluate( getPageAssertions() );
   assertions.forEach( ({ method, args }) => t[ method ]( ...args ) );
 } );
+
+test( 'checkLastPage with path: function() {}', withPage, async function( t, page ) {
+  let assertions = await page.evaluate( function() {
+    let infScroll = new InfiniteScroll( '.container', {
+      // provide only page/2.html, then falsy
+      path: function() {
+        if ( this.pageIndex < 2 ) {
+          return `page/${this.pageIndex + 1}.html`;
+        }
+      },
+      // checkLastPage: true, // true by default
+      append: '.post',
+    } );
+
+    // function returning falsey will trigger last right after pageLoad
+    let promise = new Promise( function( resolve ) {
+      infScroll.once( 'last', function() {
+        serialT.is( infScroll.pageIndex, 2 );
+        resolve( serialT.assertions );
+      } );
+    } );
+
+    // load page 2
+    infScroll.loadNextPage();
+    return promise;
+  } );
+
+  assertions.forEach( ({ method, args }) => t[ method ]( ...args ) );
+} );
diff --git a/test/html/page/empty.html b/test/html/page/empty.html
new file mode 100644
index 0000000..fe03eb0
--- /dev/null
+++ b/test/html/page/empty.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<html lang="en">
+<head>
+  <meta charset="utf-8" />
+  <meta name="viewport" content="width=device-width" />
+
+  <title>empty page</title>
+
+</head>
+<body>
+
+  <h1>empty page</h1>
+
+</body>
+</html>
diff --git a/test/outlayer.js b/test/outlayer.js
index 97a57c5..a9f36b8 100644
--- a/test/outlayer.js
+++ b/test/outlayer.js
@@ -113,20 +113,15 @@ test( 'outlayer none', withPage, async( t, page ) => {
           scrollThreshold: false,
         } );
 
-        let promises = [
-          new Promise( ( resolve ) => infScroll.once( 'load', resolve ) ),
-          new Promise( ( resolve ) => {
-            infScroll.once( 'append', function( response, path, items ) {
-              resolve( items );
-            } );
-          } ),
-        ];
+        let promise = new Promise( ( resolve ) => {
+          infScroll.once( 'load', () => {
+            serialT.pass('load triggered but not append');
+            resolve();
+          } );
+        } );
 
         infScroll.loadNextPage();
-        return Promise.all( promises );
-      } )
-      .then( ([ , items ]) => {
-        serialT.is( items.length, 0, 'appended 0 items' );
+        return promise;
       } )
       .then( () => serialT.assertions );
   } );