Repository: obsidian-tasks-group/obsidian-tasks
Pull request #3118 (2024-10-14 12:16:33)

feat: add experimental rendering of child tasks and list items
# Types of changes

Done by pairing with @claremacrae 

Changes visible to users:

- [x] **New feature** (prefix: `feat` - non-breaking change which adds functionality)
  - Issue/discussion: #60 

Internal changes:

- [x] **Tests** (prefix: `test` - additions and improvements to unit tests and the smoke tests)

## Description

- task query results now render all child list items and tasks of the tasks that match the search
- this is an experimental feature that needs more testing to ensure that it really does show every matching task

## Motivation and Context

- #60 

## How has this been tested?

- new unit tests
- exploratory testing

## Screenshots

<img width="307" alt="Снимок экрана 2024-10-14 в 18 15 49" src="https://github.com/user-attachments/assets/6ffa56ad-6c9d-4c6d-88d1-6a46426334d1">


## Checklist

- [x] My code follows the code style of this project and passes `yarn run lint`.
- [x] My change requires a change to the documentation.
- [ ] I have [updated the documentation](https://publish.obsidian.md/tasks-contributing/Documentation/About+Documentation) accordingly.
- [ ] My change has adequate [Unit Test coverage](https://publish.obsidian.md/tasks-contributing/Testing/About+Testing).

## Terms

<!--
By submitting this pull request, you must agree to follow our
[contributing guide](https://publish.obsidian.md/tasks-contributing) and
[Code of Conduct](https://github.com/obsidian-tasks-group/obsidian-tasks/blob/main/CODE_OF_CONDUCT.md).
Put an x in the boxes to confirm you agree.
-->

- [x] My contribution follows this project's [contributing guide](https://publish.obsidian.md/tasks-contributing)
- [x] I agree to follow this project's [Code of Conduct](https://github.com/obsidian-tasks-group/obsidian-tasks/blob/main/CODE_OF_CONDUCT.md)



Patch:
diff --git a/src/Renderer/QueryResultsRenderer.ts b/src/Renderer/QueryResultsRenderer.ts
index 338e4f33..702d8175 100644
--- a/src/Renderer/QueryResultsRenderer.ts
+++ b/src/Renderer/QueryResultsRenderer.ts
@@ -1,6 +1,7 @@
 import type { Component, TFile } from 'obsidian';
 import { GlobalFilter } from '../Config/GlobalFilter';
 import { GlobalQuery } from '../Config/GlobalQuery';
+import { postponeButtonTitle, shouldShowPostponeButton } from '../DateTime/Postponer';
 import type { IQuery } from '../IQuery';
 import { QueryLayout } from '../Layout/QueryLayout';
 import { TaskLayout } from '../Layout/TaskLayout';
@@ -10,9 +11,9 @@ import { State } from '../Obsidian/Cache';
 import type { GroupDisplayHeading } from '../Query/Group/GroupDisplayHeading';
 import type { TaskGroups } from '../Query/Group/TaskGroups';
 import type { QueryResult } from '../Query/QueryResult';
-import { postponeButtonTitle, shouldShowPostponeButton } from '../DateTime/Postponer';
 import type { TasksFile } from '../Scripting/TasksFile';
-import type { Task } from '../Task/Task';
+import type { ListItem } from '../Task/ListItem';
+import { Task } from '../Task/Task';
 import { PostponeMenu } from '../ui/Menus/PostponeMenu';
 import { TaskLineRenderer, type TextRenderer, createAndAppendElement } from './TaskLineRenderer';
 
@@ -188,14 +189,16 @@ export class QueryResultsRenderer {
             // will be empty, and no headings will be added.
             await this.addGroupHeadings(content, group.groupHeadings);
 
-            await this.createTaskList(group.tasks, content, queryRendererParameters);
+            const renderedTasks: Set<ListItem> = new Set();
+            await this.createTaskList(group.tasks, content, queryRendererParameters, renderedTasks);
         }
     }
 
     private async createTaskList(
-        tasks: Task[],
-        content: HTMLDivElement,
+        tasks: ListItem[],
+        content: HTMLElement,
         queryRendererParameters: QueryRendererParameters,
+        renderedTasks: Set<ListItem>,
     ): Promise<void> {
         const taskList = createAndAppendElement('ul', content);
 
@@ -217,12 +220,80 @@ export class QueryResultsRenderer {
         });
 
         for (const [taskIndex, task] of tasks.entries()) {
-            await this.addTask(taskList, taskLineRenderer, task, taskIndex, queryRendererParameters);
+            if (this.alreadyRendered(task, renderedTasks)) {
+                continue;
+            }
+
+            if (this.willBeRenderedLater(task, renderedTasks, tasks)) {
+                continue;
+            }
+
+            const listItem = await this.addTaskOrListItem(
+                taskList,
+                taskLineRenderer,
+                task,
+                taskIndex,
+                queryRendererParameters,
+            );
+            renderedTasks.add(task);
+
+            if (task.children.length > 0) {
+                await this.createTaskList(task.children, listItem, queryRendererParameters, renderedTasks);
+                task.children.forEach((childTask) => {
+                    renderedTasks.add(childTask);
+                });
+            }
         }
 
         content.appendChild(taskList);
     }
 
+    private willBeRenderedLater(task: ListItem, renderedTasks: Set<ListItem>, tasks: ListItem[]) {
+        // Try to find the closest parent that is a task
+        let closestParentTask = task.parent;
+        while (closestParentTask !== null && !(closestParentTask instanceof Task)) {
+            closestParentTask = closestParentTask.parent;
+        }
+
+        if (!closestParentTask) {
+            return false;
+        }
+
+        if (!renderedTasks.has(closestParentTask)) {
+            // This task is a direct or indirect child of another task that we are waiting to draw,
+            // so don't draw it yet, it will be done recursively later.
+            if (tasks.includes(closestParentTask)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private alreadyRendered(task: ListItem, renderedTasks: Set<ListItem>) {
+        return renderedTasks.has(task);
+    }
+
+    private async addTaskOrListItem(
+        taskList: HTMLUListElement,
+        taskLineRenderer: TaskLineRenderer,
+        task: ListItem,
+        taskIndex: number,
+        queryRendererParameters: QueryRendererParameters,
+    ) {
+        if (task instanceof Task) {
+            return await this.addTask(taskList, taskLineRenderer, task, taskIndex, queryRendererParameters);
+        }
+
+        return this.addListItem(taskList, task);
+    }
+
+    private addListItem(taskList: HTMLUListElement, listItem: ListItem) {
+        const li = createAndAppendElement('li', taskList);
+        li.textContent = listItem.originalMarkdown;
+        return li;
+    }
+
     private async addTask(
         taskList: HTMLUListElement,
         taskLineRenderer: TaskLineRenderer,
@@ -259,6 +330,8 @@ export class QueryResultsRenderer {
         }
 
         taskList.appendChild(listItem);
+
+        return listItem;
     }
 
     private addEditButton(listItem: HTMLElement, task: Task, queryRendererParameters: QueryRendererParameters) {


Test patch:
diff --git a/tests/Renderer/QueryResultsRenderer.test.QueryResultsRenderer_tests_parent-child_items.approved.html b/tests/Renderer/QueryResultsRenderer.test.QueryResultsRenderer_tests_parent-child_items.approved.html
index 78627a4a..421ee935 100644
--- a/tests/Renderer/QueryResultsRenderer.test.QueryResultsRenderer_tests_parent-child_items.approved.html
+++ b/tests/Renderer/QueryResultsRenderer.test.QueryResultsRenderer_tests_parent-child_items.approved.html
@@ -19,86 +19,104 @@
         </span>
         <a class="tasks-edit" title="Edit task" href="#"></a>
       </span>
-    </li>
-    <li
-      class="task-list-item plugin-tasks-list-item"
-      data-task-priority="normal"
-      data-task=""
-      data-line="1"
-      data-task-status-name="Todo"
-      data-task-status-type="TODO">
-      <input class="task-list-item-checkbox" type="checkbox" title="Right-click for options" data-line="1" />
-      <span class="tasks-list-text">
-        <span class="task-description"><span>child 1</span></span>
-      </span>
-      <span class="task-extras">
-        <span class="tasks-backlink">
-          (
-          <a rel="noopener" target="_blank" class="internal-link">inheritance_rendering_sample</a>
-          )
-        </span>
-        <a class="tasks-edit" title="Edit task" href="#"></a>
-      </span>
-    </li>
-    <li
-      class="task-list-item plugin-tasks-list-item"
-      data-task-priority="normal"
-      data-task=""
-      data-line="2"
-      data-task-status-name="Todo"
-      data-task-status-type="TODO">
-      <input class="task-list-item-checkbox" type="checkbox" title="Right-click for options" data-line="2" />
-      <span class="tasks-list-text">
-        <span class="task-description"><span>grandchild 1</span></span>
-      </span>
-      <span class="task-extras">
-        <span class="tasks-backlink">
-          (
-          <a rel="noopener" target="_blank" class="internal-link">inheritance_rendering_sample</a>
-          )
-        </span>
-        <a class="tasks-edit" title="Edit task" href="#"></a>
-      </span>
-    </li>
-    <li
-      class="task-list-item plugin-tasks-list-item"
-      data-task-priority="normal"
-      data-task=""
-      data-line="3"
-      data-task-status-name="Todo"
-      data-task-status-type="TODO">
-      <input class="task-list-item-checkbox" type="checkbox" title="Right-click for options" data-line="3" />
-      <span class="tasks-list-text">
-        <span class="task-description"><span>child 2</span></span>
-      </span>
-      <span class="task-extras">
-        <span class="tasks-backlink">
-          (
-          <a rel="noopener" target="_blank" class="internal-link">inheritance_rendering_sample</a>
-          )
-        </span>
-        <a class="tasks-edit" title="Edit task" href="#"></a>
-      </span>
-    </li>
-    <li
-      class="task-list-item plugin-tasks-list-item"
-      data-task-priority="normal"
-      data-task=""
-      data-line="4"
-      data-task-status-name="Todo"
-      data-task-status-type="TODO">
-      <input class="task-list-item-checkbox" type="checkbox" title="Right-click for options" data-line="4" />
-      <span class="tasks-list-text">
-        <span class="task-description"><span>grand grand child</span></span>
-      </span>
-      <span class="task-extras">
-        <span class="tasks-backlink">
-          (
-          <a rel="noopener" target="_blank" class="internal-link">inheritance_rendering_sample</a>
-          )
-        </span>
-        <a class="tasks-edit" title="Edit task" href="#"></a>
-      </span>
+      <ul class="contains-task-list plugin-tasks-query-result tasks-layout-hide-urgency">
+        <li
+          class="task-list-item plugin-tasks-list-item"
+          data-task-priority="normal"
+          data-task=""
+          data-line="0"
+          data-task-status-name="Todo"
+          data-task-status-type="TODO">
+          <input class="task-list-item-checkbox" type="checkbox" title="Right-click for options" data-line="0" />
+          <span class="tasks-list-text">
+            <span class="task-description"><span>child 1</span></span>
+          </span>
+          <span class="task-extras">
+            <span class="tasks-backlink">
+              (
+              <a rel="noopener" target="_blank" class="internal-link">inheritance_rendering_sample</a>
+              )
+            </span>
+            <a class="tasks-edit" title="Edit task" href="#"></a>
+          </span>
+          <ul class="contains-task-list plugin-tasks-query-result tasks-layout-hide-urgency">
+            <li
+              class="task-list-item plugin-tasks-list-item"
+              data-task-priority="normal"
+              data-task=""
+              data-line="0"
+              data-task-status-name="Todo"
+              data-task-status-type="TODO">
+              <input class="task-list-item-checkbox" type="checkbox" title="Right-click for options" data-line="0" />
+              <span class="tasks-list-text">
+                <span class="task-description"><span>grandchild 1</span></span>
+              </span>
+              <span class="task-extras">
+                <span class="tasks-backlink">
+                  (
+                  <a rel="noopener" target="_blank" class="internal-link">inheritance_rendering_sample</a>
+                  )
+                </span>
+                <a class="tasks-edit" title="Edit task" href="#"></a>
+              </span>
+              <ul class="contains-task-list plugin-tasks-query-result tasks-layout-hide-urgency">
+                <li>- list item grand grand child</li>
+              </ul>
+            </li>
+          </ul>
+        </li>
+        <li
+          class="task-list-item plugin-tasks-list-item"
+          data-task-priority="normal"
+          data-task=""
+          data-line="1"
+          data-task-status-name="Todo"
+          data-task-status-type="TODO">
+          <input class="task-list-item-checkbox" type="checkbox" title="Right-click for options" data-line="1" />
+          <span class="tasks-list-text">
+            <span class="task-description"><span>child 2</span></span>
+          </span>
+          <span class="task-extras">
+            <span class="tasks-backlink">
+              (
+              <a rel="noopener" target="_blank" class="internal-link">inheritance_rendering_sample</a>
+              )
+            </span>
+            <a class="tasks-edit" title="Edit task" href="#"></a>
+          </span>
+          <ul class="contains-task-list plugin-tasks-query-result tasks-layout-hide-urgency">
+            <li>
+              - non task grandchild
+              <ul class="contains-task-list plugin-tasks-query-result tasks-layout-hide-urgency">
+                <li
+                  class="task-list-item plugin-tasks-list-item"
+                  data-task-priority="normal"
+                  data-task=""
+                  data-line="0"
+                  data-task-status-name="Todo"
+                  data-task-status-type="TODO">
+                  <input
+                    class="task-list-item-checkbox"
+                    type="checkbox"
+                    title="Right-click for options"
+                    data-line="0" />
+                  <span class="tasks-list-text">
+                    <span class="task-description"><span>grand grand child</span></span>
+                  </span>
+                  <span class="task-extras">
+                    <span class="tasks-backlink">
+                      (
+                      <a rel="noopener" target="_blank" class="internal-link">inheritance_rendering_sample</a>
+                      )
+                    </span>
+                    <a class="tasks-edit" title="Edit task" href="#"></a>
+                  </span>
+                </li>
+              </ul>
+            </li>
+          </ul>
+        </li>
+      </ul>
     </li>
     <li
       class="task-list-item plugin-tasks-list-item"
diff --git a/tests/Renderer/QueryResultsRenderer.test.QueryResultsRenderer_tests_parent-child_items_reverse_sorted.approved.html b/tests/Renderer/QueryResultsRenderer.test.QueryResultsRenderer_tests_parent-child_items_reverse_sorted.approved.html
new file mode 100644
index 00000000..0eb0b484
--- /dev/null
+++ b/tests/Renderer/QueryResultsRenderer.test.QueryResultsRenderer_tests_parent-child_items_reverse_sorted.approved.html
@@ -0,0 +1,143 @@
+<div>
+  <ul class="contains-task-list plugin-tasks-query-result tasks-layout-hide-urgency">
+    <li
+      class="task-list-item plugin-tasks-list-item"
+      data-task-priority="normal"
+      data-task=""
+      data-line="0"
+      data-task-status-name="Todo"
+      data-task-status-type="TODO">
+      <input class="task-list-item-checkbox" type="checkbox" title="Right-click for options" data-line="0" />
+      <span class="tasks-list-text">
+        <span class="task-description"><span>parent 2</span></span>
+      </span>
+      <span class="task-extras">
+        <span class="tasks-backlink">
+          (
+          <a rel="noopener" target="_blank" class="internal-link">inheritance_rendering_sample</a>
+          )
+        </span>
+        <a class="tasks-edit" title="Edit task" href="#"></a>
+      </span>
+    </li>
+    <li
+      class="task-list-item plugin-tasks-list-item"
+      data-task-priority="normal"
+      data-task=""
+      data-line="5"
+      data-task-status-name="Todo"
+      data-task-status-type="TODO">
+      <input class="task-list-item-checkbox" type="checkbox" title="Right-click for options" data-line="5" />
+      <span class="tasks-list-text">
+        <span class="task-description"><span>parent 1</span></span>
+      </span>
+      <span class="task-extras">
+        <span class="tasks-backlink">
+          (
+          <a rel="noopener" target="_blank" class="internal-link">inheritance_rendering_sample</a>
+          )
+        </span>
+        <a class="tasks-edit" title="Edit task" href="#"></a>
+      </span>
+      <ul class="contains-task-list plugin-tasks-query-result tasks-layout-hide-urgency">
+        <li
+          class="task-list-item plugin-tasks-list-item"
+          data-task-priority="normal"
+          data-task=""
+          data-line="0"
+          data-task-status-name="Todo"
+          data-task-status-type="TODO">
+          <input class="task-list-item-checkbox" type="checkbox" title="Right-click for options" data-line="0" />
+          <span class="tasks-list-text">
+            <span class="task-description"><span>child 1</span></span>
+          </span>
+          <span class="task-extras">
+            <span class="tasks-backlink">
+              (
+              <a rel="noopener" target="_blank" class="internal-link">inheritance_rendering_sample</a>
+              )
+            </span>
+            <a class="tasks-edit" title="Edit task" href="#"></a>
+          </span>
+          <ul class="contains-task-list plugin-tasks-query-result tasks-layout-hide-urgency">
+            <li
+              class="task-list-item plugin-tasks-list-item"
+              data-task-priority="normal"
+              data-task=""
+              data-line="0"
+              data-task-status-name="Todo"
+              data-task-status-type="TODO">
+              <input class="task-list-item-checkbox" type="checkbox" title="Right-click for options" data-line="0" />
+              <span class="tasks-list-text">
+                <span class="task-description"><span>grandchild 1</span></span>
+              </span>
+              <span class="task-extras">
+                <span class="tasks-backlink">
+                  (
+                  <a rel="noopener" target="_blank" class="internal-link">inheritance_rendering_sample</a>
+                  )
+                </span>
+                <a class="tasks-edit" title="Edit task" href="#"></a>
+              </span>
+              <ul class="contains-task-list plugin-tasks-query-result tasks-layout-hide-urgency">
+                <li>- list item grand grand child</li>
+              </ul>
+            </li>
+          </ul>
+        </li>
+        <li
+          class="task-list-item plugin-tasks-list-item"
+          data-task-priority="normal"
+          data-task=""
+          data-line="1"
+          data-task-status-name="Todo"
+          data-task-status-type="TODO">
+          <input class="task-list-item-checkbox" type="checkbox" title="Right-click for options" data-line="1" />
+          <span class="tasks-list-text">
+            <span class="task-description"><span>child 2</span></span>
+          </span>
+          <span class="task-extras">
+            <span class="tasks-backlink">
+              (
+              <a rel="noopener" target="_blank" class="internal-link">inheritance_rendering_sample</a>
+              )
+            </span>
+            <a class="tasks-edit" title="Edit task" href="#"></a>
+          </span>
+          <ul class="contains-task-list plugin-tasks-query-result tasks-layout-hide-urgency">
+            <li>
+              - non task grandchild
+              <ul class="contains-task-list plugin-tasks-query-result tasks-layout-hide-urgency">
+                <li
+                  class="task-list-item plugin-tasks-list-item"
+                  data-task-priority="normal"
+                  data-task=""
+                  data-line="0"
+                  data-task-status-name="Todo"
+                  data-task-status-type="TODO">
+                  <input
+                    class="task-list-item-checkbox"
+                    type="checkbox"
+                    title="Right-click for options"
+                    data-line="0" />
+                  <span class="tasks-list-text">
+                    <span class="task-description"><span>grand grand child</span></span>
+                  </span>
+                  <span class="task-extras">
+                    <span class="tasks-backlink">
+                      (
+                      <a rel="noopener" target="_blank" class="internal-link">inheritance_rendering_sample</a>
+                      )
+                    </span>
+                    <a class="tasks-edit" title="Edit task" href="#"></a>
+                  </span>
+                </li>
+              </ul>
+            </li>
+          </ul>
+        </li>
+      </ul>
+    </li>
+  </ul>
+  <div class="task-count">6 tasks</div>
+</div>
diff --git a/tests/Renderer/QueryResultsRenderer.test.QueryResultsRenderer_tests_should_render_tasks_without_their_parents.approved.html b/tests/Renderer/QueryResultsRenderer.test.QueryResultsRenderer_tests_should_render_tasks_without_their_parents.approved.html
new file mode 100644
index 00000000..84b498de
--- /dev/null
+++ b/tests/Renderer/QueryResultsRenderer.test.QueryResultsRenderer_tests_should_render_tasks_without_their_parents.approved.html
@@ -0,0 +1,65 @@
+<div>
+  <ul class="contains-task-list plugin-tasks-query-result tasks-layout-hide-urgency">
+    <li
+      class="task-list-item plugin-tasks-list-item"
+      data-task-priority="normal"
+      data-task=""
+      data-line="0"
+      data-task-status-name="Todo"
+      data-task-status-type="TODO">
+      <input class="task-list-item-checkbox" type="checkbox" title="Right-click for options" data-line="0" />
+      <span class="tasks-list-text">
+        <span class="task-description"><span>grandchild task 1</span></span>
+      </span>
+      <span class="task-extras">
+        <span class="tasks-backlink">
+          (
+          <a rel="noopener" target="_blank" class="internal-link">inheritance_task_2listitem_3task</a>
+          )
+        </span>
+        <a class="tasks-edit" title="Edit task" href="#"></a>
+      </span>
+    </li>
+    <li
+      class="task-list-item plugin-tasks-list-item"
+      data-task-priority="normal"
+      data-task=""
+      data-line="1"
+      data-task-status-name="Todo"
+      data-task-status-type="TODO">
+      <input class="task-list-item-checkbox" type="checkbox" title="Right-click for options" data-line="1" />
+      <span class="tasks-list-text">
+        <span class="task-description"><span>grandchild task 2</span></span>
+      </span>
+      <span class="task-extras">
+        <span class="tasks-backlink">
+          (
+          <a rel="noopener" target="_blank" class="internal-link">inheritance_task_2listitem_3task</a>
+          )
+        </span>
+        <a class="tasks-edit" title="Edit task" href="#"></a>
+      </span>
+    </li>
+    <li
+      class="task-list-item plugin-tasks-list-item"
+      data-task-priority="normal"
+      data-task=""
+      data-line="2"
+      data-task-status-name="Todo"
+      data-task-status-type="TODO">
+      <input class="task-list-item-checkbox" type="checkbox" title="Right-click for options" data-line="2" />
+      <span class="tasks-list-text">
+        <span class="task-description"><span>grandchild task 3</span></span>
+      </span>
+      <span class="task-extras">
+        <span class="tasks-backlink">
+          (
+          <a rel="noopener" target="_blank" class="internal-link">inheritance_task_2listitem_3task</a>
+          )
+        </span>
+        <a class="tasks-edit" title="Edit task" href="#"></a>
+      </span>
+    </li>
+  </ul>
+  <div class="task-count">3 tasks</div>
+</div>
diff --git a/tests/Renderer/QueryResultsRenderer.test.ts b/tests/Renderer/QueryResultsRenderer.test.ts
index 70eed720..e3f7e89a 100644
--- a/tests/Renderer/QueryResultsRenderer.test.ts
+++ b/tests/Renderer/QueryResultsRenderer.test.ts
@@ -7,6 +7,7 @@ import { State } from '../../src/Obsidian/Cache';
 import { QueryResultsRenderer } from '../../src/Renderer/QueryResultsRenderer';
 import { TasksFile } from '../../src/Scripting/TasksFile';
 import { inheritance_rendering_sample } from '../Obsidian/__test_data__/inheritance_rendering_sample';
+import { inheritance_task_2listitem_3task } from '../Obsidian/__test_data__/inheritance_task_2listitem_3task';
 import { readTasksFromSimulatedFile } from '../Obsidian/SimulatedFile';
 import { verifyWithFileExtension } from '../TestingTools/ApprovalTestHelpers';
 import { prettifyHTML } from '../TestingTools/HTMLHelpers';
@@ -25,10 +26,10 @@ afterEach(() => {
 });
 
 describe('QueryResultsRenderer tests', () => {
-    async function verifyRenderedTasksHTML(allTasks: Task[]) {
+    async function verifyRenderedTasksHTML(allTasks: Task[], source: string = '') {
         const renderer = new QueryResultsRenderer(
             'block-language-tasks',
-            '',
+            source,
             new TasksFile('query.md'),
             () => Promise.resolve(),
             null,
@@ -56,6 +57,17 @@ describe('QueryResultsRenderer tests', () => {
 
     it('parent-child items', async () => {
         const allTasks = readTasksFromSimulatedFile(inheritance_rendering_sample);
-        await verifyRenderedTasksHTML(allTasks);
+        await verifyRenderedTasksHTML(allTasks, 'sort by function task.lineNumber');
+    });
+
+    it('parent-child items reverse sorted', async () => {
+        const allTasks = readTasksFromSimulatedFile(inheritance_rendering_sample);
+        await verifyRenderedTasksHTML(allTasks, 'sort by function reverse task.lineNumber');
+    });
+
+    it('should render tasks without their parents', async () => {
+        // example chosen to match subtasks whose parents do not match the query
+        const allTasks = readTasksFromSimulatedFile(inheritance_task_2listitem_3task);
+        await verifyRenderedTasksHTML(allTasks, 'description includes grandchild');
     });
 });