Repository: obsidian-tasks-group/obsidian-tasks (ts)

Issue:
Make 'explain' explain group commands
### Motivation

At the moment the `group by` instructions are not included in `explain` output.

This would have been useful in investigating this problem, for example:
https://github.com/obsidian-tasks-group/obsidian-tasks/issues/1461#issuecomment-1622749193

It will also help show any `group by` instructions in the global filter.

### Implementation

Currently Query stores only the name of the type of the `group by` line and not the whole line:

https://github.com/obsidian-tasks-group/obsidian-tasks/blob/6da15e6feeaddb4a52df96e799ff0b8a1e5a1967/src/Query/Query.ts#L23

https://github.com/obsidian-tasks-group/obsidian-tasks/blob/650cd22b6c1661ee92d71957983b5ded1f631608/src/Query/Grouper.ts#L23-L40

So this change will likely involve changing `Grouper` to store the instruction and the explanation, similar to how `Filter` does:

https://github.com/obsidian-tasks-group/obsidian-tasks/blob/7c19f3fb4fd0b1aa73c663ff19a0f34511bced3b/src/Query/Filter/Filter.ts#L20-L23

_Originally posted by @claremacrae in https://github.com/obsidian-tasks-group/obsidian-tasks/issues/2093#issuecomment-1623348346_
            

Pull request:
feat: Make 'explain' show 'group by' commands
<!--- Provide a general summary of your changes in the Title above -->

# Description

1. Make `explain` list the Query's `group by` instructions.
2. Update the documentation

The white-spacing is not super consistent with other instructions. Sometimes there are two blanks instead of one - but I will tidy that up later on. The main thing is that the information is present now.


## Motivation and Context

Fixes #2105.

This is part of preparation for #2074 - I want to be able to show what `group by` instructions are in use, and test the removal of them via something like `clear group by`.

## How has this been tested?

<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, tests ran to see how -->
<!--- your change affects other areas of the code, etc. -->

- Via tests
- Via exploratory testing

## Screenshots (if appropriate)

![image](https://github.com/obsidian-tasks-group/obsidian-tasks/assets/4840096/0491556c-0bbd-49d5-bba1-1f167410813f)


## Types of changes

<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->

Changes visible to users:

- [x] **New feature** (prefix: `feat` - non-breaking change which adds functionality)
- [x] **Documentation** (prefix: `docs` - improvements to any documentation content **for users**)

Internal changes:

- [x] **Refactor** (prefix: `refactor` - non-breaking change which only improves the design or structure of existing code, and making no changes to its external behaviour)
- [x] **Tests** (prefix: `test` - additions and improvements to unit tests and the smoke tests)

## Checklist

<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->

- [x] My code follows the code style of this project and passes `yarn run lint`.
- [x] My change requires a change to the documentation.
- [x] I have [updated the documentation](https://publish.obsidian.md/tasks-contributing/Documentation/About+Documentation) accordingly.
- [x] 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 follow 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/docs/Introduction.md b/docs/Introduction.md
index 40525154..4227bc35 100644
--- a/docs/Introduction.md
+++ b/docs/Introduction.md
@@ -14,6 +14,7 @@ _In recent [releases](https://github.com/obsidian-tasks-group/obsidian-tasks/rel
 -->
 
 - X.Y.Z: 🔥 Add [[Layout#Full Mode|'full mode']] to turn off `short mode`.
+- X.Y.Z: 🔥 Add any [[Grouping|'group by']] instructions to [[Explaining Queries|explain]] output.
 - 5.3.0: 🔥 Add [[Postponing|postpone button]] to Tasks query results.
 - 5.3.0: 🔥 Add [[Toggling and Editing Statuses#'Change task status' context menu|'change task status' menu]] to Reading mode and Tasks query results.
 - 5.3.0: 🔥 Add documentation section about [[About Editing|editing tasks]].
diff --git a/docs/Queries/Explaining Queries.md b/docs/Queries/Explaining Queries.md
index 21878a1f..4008407a 100644
--- a/docs/Queries/Explaining Queries.md
+++ b/docs/Queries/Explaining Queries.md
@@ -20,6 +20,7 @@ This has a number of benefits:
 - If there is a [[Global Filter|global filter]] enabled, it is included in the explanation.
   - This often explains why tasks are missing from results.
 - If there is a [[Global Query|global query]] enabled, it too is included in the explanation.
+- Any [[Grouping|'group by']] instructions are listed (since Tasks X.Y.Z)
 
 ## Examples
 
@@ -50,6 +51,8 @@ scheduled after 1 week ago =>
 
 due before tomorrow =>
   due date is before 2022-10-22 (Saturday 22nd October 2022)
+
+No grouping instructions supplied.
 ```
 <!-- endSnippet -->
 
@@ -79,6 +82,8 @@ Explanation of this Tasks code block query:
 
 path regex matches /^Root/Sub-Folder/Sample File\.md/i =>
   using regex:     '^Root\/Sub-Folder\/Sample File\.md' with flag 'i'
+
+No grouping instructions supplied.
 ```
 <!-- endSnippet -->
 
@@ -106,6 +111,8 @@ not done
   AND (All of):
     due date is before 2022-10-22 (Saturday 22nd October 2022)
     is recurring
+
+No grouping instructions supplied.
 ```
 <!-- endSnippet -->
 
@@ -148,6 +155,8 @@ Explanation of this Tasks code block query:
         description includes 7
       NOT:
         description includes 7
+
+No grouping instructions supplied.
 ```
 <!-- endSnippet -->
 
@@ -183,6 +192,8 @@ Explanation of the global query:
 
 heading includes tasks
 
+No grouping instructions supplied.
+
 
 At most 50 tasks.
 
@@ -194,6 +205,8 @@ due next week =>
   due date is between:
     2022-10-24 (Monday 24th October 2022) and
     2022-10-30 (Sunday 30th October 2022) inclusive
+
+No grouping instructions supplied.
 ```
 <!-- endSnippet -->
 
@@ -230,7 +243,9 @@ folder includes some/sample/
 
 filename includes file path.md
 
-description includes Some Cryptic String
+description includes Some Cryptic String 
+
+No grouping instructions supplied.
 ```
 <!-- endSnippet -->
 
diff --git a/docs/Queries/Line Continuations.md b/docs/Queries/Line Continuations.md
index a9bbb768..f4bf8844 100644
--- a/docs/Queries/Line Continuations.md
+++ b/docs/Queries/Line Continuations.md
@@ -35,6 +35,8 @@ Explanation of this Tasks code block query:
   OR (At least one of):
     priority is highest
     priority is lowest
+
+No grouping instructions supplied.
 ```
 <!-- endSnippet -->
 
@@ -73,6 +75,8 @@ explain
 Explanation of this Tasks code block query:
 
 description includes \
+
+No grouping instructions supplied.
 ```
 <!-- endSnippet -->
 
diff --git a/docs/Queries/Regular Expressions.md b/docs/Queries/Regular Expressions.md
index d8187ce5..d0234df6 100644
--- a/docs/Queries/Regular Expressions.md
+++ b/docs/Queries/Regular Expressions.md
@@ -97,6 +97,8 @@ Explanation of this Tasks code block query:
 
 path regex matches /^Root/Sub-Folder/Sample File\.md/i =>
   using regex:     '^Root\/Sub-Folder\/Sample File\.md' with flag 'i'
+
+No grouping instructions supplied.
 ```
 <!-- endSnippet -->
 
diff --git a/docs/Scripting/Placeholders.md b/docs/Scripting/Placeholders.md
index 50e3bb4b..ac44d588 100644
--- a/docs/Scripting/Placeholders.md
+++ b/docs/Scripting/Placeholders.md
@@ -51,7 +51,9 @@ folder includes some/sample/
 
 filename includes file path.md
 
-description includes Some Cryptic String
+description includes Some Cryptic String 
+
+No grouping instructions supplied.
 ```
 <!-- endSnippet -->
 
diff --git a/src/Query/Filter/Field.ts b/src/Query/Filter/Field.ts
index c03f2d90..2b92c029 100644
--- a/src/Query/Filter/Field.ts
+++ b/src/Query/Filter/Field.ts
@@ -272,6 +272,21 @@ export abstract class Field {
         return new RegExp(`^group by ${this.fieldNameSingularEscaped()}( reverse)?$`, 'i');
     }
 
+    /**
+     * Reconstruct a 'group by' instruction to use for grouping of this field.
+     *
+     * This is used to simplify the construction of Grouper objects.
+     * @param reverse
+     * @protected
+     */
+    protected grouperInstruction(reverse: boolean) {
+        let instruction = `group by ${this.fieldNameSingular()}`;
+        if (reverse) {
+            instruction += ' reverse';
+        }
+        return instruction;
+    }
+
     /**
      * Return a function to get a list of a task's group names, for use in grouping by this field's value.
      *
@@ -287,7 +302,7 @@ export abstract class Field {
      * @param reverse - false for normal group order, true for reverse group order.
      */
     public createGrouper(reverse: boolean): Grouper {
-        return new Grouper(this.fieldNameSingular(), this.grouper(), reverse);
+        return new Grouper(this.grouperInstruction(reverse), this.fieldNameSingular(), this.grouper(), reverse);
     }
 
     /**
diff --git a/src/Query/Filter/FunctionField.ts b/src/Query/Filter/FunctionField.ts
index 6fde564a..eac119ee 100644
--- a/src/Query/Filter/FunctionField.ts
+++ b/src/Query/Filter/FunctionField.ts
@@ -55,7 +55,7 @@ export class FunctionField extends Field {
         }
         const reverse = !!match[1];
         const args = match[2];
-        return new Grouper('function', createGrouperFunctionFromLine(args), reverse);
+        return new Grouper(line, 'function', createGrouperFunctionFromLine(args), reverse);
     }
 
     protected grouperRegExp(): RegExp {
diff --git a/src/Query/Filter/MultiTextField.ts b/src/Query/Filter/MultiTextField.ts
index ce5fe474..617b6d4e 100644
--- a/src/Query/Filter/MultiTextField.ts
+++ b/src/Query/Filter/MultiTextField.ts
@@ -64,7 +64,7 @@ export abstract class MultiTextField extends TextField {
      * This overloads {@link Field.createGrouper} to put a plural field name in the {@link Grouper.property}.
      */
     public createGrouper(reverse: boolean): Grouper {
-        return new Grouper(this.fieldNamePlural(), this.grouper(), reverse);
+        return new Grouper(this.grouperInstruction(reverse), this.fieldNamePlural(), this.grouper(), reverse);
     }
 
     protected grouperRegExp(): RegExp {
@@ -74,4 +74,12 @@ export abstract class MultiTextField extends TextField {
 
         return new RegExp(`^group by ${this.fieldNamePlural()}( reverse)?$`, 'i');
     }
+
+    protected grouperInstruction(reverse: boolean) {
+        let instruction = `group by ${this.fieldNamePlural()}`;
+        if (reverse) {
+            instruction += ' reverse';
+        }
+        return instruction;
+    }
 }
diff --git a/src/Query/Filter/UrgencyField.ts b/src/Query/Filter/UrgencyField.ts
index 4718d997..bb36afc7 100644
--- a/src/Query/Filter/UrgencyField.ts
+++ b/src/Query/Filter/UrgencyField.ts
@@ -70,4 +70,8 @@ export class UrgencyField extends Field {
     public createGrouper(reverse: boolean): Grouper {
         return super.createGrouper(!reverse);
     }
+
+    protected grouperInstruction(reverse: boolean) {
+        return super.grouperInstruction(!reverse);
+    }
 }
diff --git a/src/Query/Grouper.ts b/src/Query/Grouper.ts
index 919af6e1..4f37afe8 100644
--- a/src/Query/Grouper.ts
+++ b/src/Query/Grouper.ts
@@ -25,6 +25,8 @@ export type GrouperFunction = (task: Task, searchInfo: SearchInfo) => string[];
  * @see {@link TaskGroups} for how to use {@link Grouper} objects to group tasks together.
  */
 export class Grouper {
+    public instruction: string;
+
     /**
      * The type of grouper, for example 'tags' or 'due'.
      *
@@ -43,7 +45,8 @@ export class Grouper {
      */
     public readonly reverse: boolean;
 
-    constructor(property: string, grouper: GrouperFunction, reverse: boolean) {
+    constructor(instruction: string, property: string, grouper: GrouperFunction, reverse: boolean) {
+        this.instruction = instruction;
         this.property = property;
         this.grouper = grouper;
         this.reverse = reverse;
diff --git a/src/Query/Query.ts b/src/Query/Query.ts
index b00a7e25..2ae48338 100644
--- a/src/Query/Query.ts
+++ b/src/Query/Query.ts
@@ -173,6 +173,7 @@ ${source}`;
         }
 
         result += this.explainFilters();
+        result += this.explainGroups();
         result += this.explainQueryLimits();
 
         const { debugSettings } = getSettings();
@@ -184,7 +185,7 @@ ${source}`;
         return result;
     }
 
-    private explainFilters() {
+    public explainFilters() {
         let result = '';
         const numberOfFilters = this.filters.length;
         if (numberOfFilters === 0) {
@@ -198,6 +199,20 @@ ${source}`;
         return result;
     }
 
+    private explainGroups() {
+        let result = '\n';
+        const numberOfGroups = this.grouping.length;
+        if (numberOfGroups === 0) {
+            result += 'No grouping instructions supplied.\n';
+        } else {
+            for (let i = 0; i < numberOfGroups; i++) {
+                if (i > 0) result += '\n';
+                result += this.grouping[i].instruction;
+            }
+        }
+        return result;
+    }
+
     private explainQueryLimits() {
         let result = '';
 


Test patch:
diff --git a/tests/Config/DebugSettings.test.ts b/tests/Config/DebugSettings.test.ts
index 7b2a345a..5f71ba9d 100644
--- a/tests/Config/DebugSettings.test.ts
+++ b/tests/Config/DebugSettings.test.ts
@@ -36,6 +36,8 @@ describe('DebugSettings', () => {
 
         expect(query.explainQuery()).toMatchInlineSnapshot(`
             "No filters supplied. All tasks will match the query.
+            No grouping instructions supplied.
+
 
             NOTE: All sort instructions, including default sort order, are disabled, due to 'ignoreSortInstructions' setting."
         `);
diff --git a/tests/Query.test.ts b/tests/Query.test.ts
index 865f5196..30c16abb 100644
--- a/tests/Query.test.ts
+++ b/tests/Query.test.ts
@@ -358,6 +358,7 @@ describe('Query parsing', () => {
             expect(query.error).toBeUndefined();
             expect(query.grouping.length).toEqual(1);
             expect(query.grouping[0]).toBeDefined();
+            expect(query.grouping[0].instruction).toEqual(filter);
 
             // Assert
             expect(queryUpperCase.error).toBeUndefined();
@@ -1196,9 +1197,11 @@ describe('Query', () => {
         it('should explain 0 filters', () => {
             const source = '';
             const query = new Query(source);
-            expect(query.explainQuery()).toMatchInlineSnapshot(
-                '"No filters supplied. All tasks will match the query."',
-            );
+            expect(query.explainQuery()).toMatchInlineSnapshot(`
+                "No filters supplied. All tasks will match the query.
+                No grouping instructions supplied.
+                "
+            `);
         });
 
         it('should explain 1 filter', () => {
@@ -1206,6 +1209,8 @@ describe('Query', () => {
             const query = new Query(source);
             expect(query.explainQuery()).toMatchInlineSnapshot(`
                 "description includes hello
+
+                No grouping instructions supplied.
                 "
             `);
         });
@@ -1218,6 +1223,8 @@ describe('Query', () => {
 
                 due 2012-01-23 =>
                   due date is on 2012-01-23 (Monday 23rd January 2012)
+
+                No grouping instructions supplied.
                 "
             `);
         });
@@ -1238,6 +1245,8 @@ describe('Query', () => {
             const query = new Query(source);
             expect(query.explainQuery()).toMatchInlineSnapshot(`
                 "No filters supplied. All tasks will match the query.
+                No grouping instructions supplied.
+
 
                 At most 5 tasks.
                 "
@@ -1249,6 +1258,8 @@ describe('Query', () => {
             const query = new Query(source);
             expect(query.explainQuery()).toMatchInlineSnapshot(`
                 "No filters supplied. All tasks will match the query.
+                No grouping instructions supplied.
+
 
                 At most 1 task.
                 "
@@ -1260,6 +1271,8 @@ describe('Query', () => {
             const query = new Query(source);
             expect(query.explainQuery()).toMatchInlineSnapshot(`
                 "No filters supplied. All tasks will match the query.
+                No grouping instructions supplied.
+
 
                 At most 0 tasks.
                 "
@@ -1271,6 +1284,8 @@ describe('Query', () => {
             const query = new Query(source);
             expect(query.explainQuery()).toMatchInlineSnapshot(`
                 "No filters supplied. All tasks will match the query.
+                No grouping instructions supplied.
+
 
                 At most 4 tasks per group (if any "group by" options are supplied).
                 "
@@ -1282,6 +1297,8 @@ describe('Query', () => {
             const query = new Query(source);
             expect(query.explainQuery()).toMatchInlineSnapshot(`
                 "No filters supplied. All tasks will match the query.
+                No grouping instructions supplied.
+
 
                 At most 127 tasks.
 
@@ -1290,6 +1307,18 @@ describe('Query', () => {
                 "
             `);
         });
+
+        it('should explain "group by" options', () => {
+            const source =
+                'group by due\ngroup by status.name reverse\ngroup by function task.description.toUpperCase()';
+            const query = new Query(source);
+            expect(query.explainQuery()).toMatchInlineSnapshot(`
+                "No filters supplied. All tasks will match the query.
+                group by due
+                group by status.name reverse
+                group by function task.description.toUpperCase()"
+            `);
+        });
     });
 
     // This tests the parsing of 'group by' instructions.
@@ -1526,6 +1555,8 @@ with \ backslash)`;
                   OR (At least one of):
                     description includes line 1
                     description includes line 1 continued with \\ backslash
+
+                No grouping instructions supplied.
                 "
             `);
             expect(queryUpperCase.explainQuery()).toMatchInlineSnapshot(`
@@ -1533,6 +1564,8 @@ with \ backslash)`;
                   OR (At least one of):
                     description includes line 1
                     description includes line 1 continued with \\ backslash
+
+                No grouping instructions supplied.
                 "
             `);
         });
diff --git a/tests/Query/Explain/DocsSamplesForExplain.test.explain_boolean_combinations.approved.explanation.text b/tests/Query/Explain/DocsSamplesForExplain.test.explain_boolean_combinations.approved.explanation.text
index 21cd27ac..d31a329a 100644
--- a/tests/Query/Explain/DocsSamplesForExplain.test.explain_boolean_combinations.approved.explanation.text
+++ b/tests/Query/Explain/DocsSamplesForExplain.test.explain_boolean_combinations.approved.explanation.text
@@ -6,3 +6,5 @@ not done
   AND (All of):
     due date is before 2022-10-22 (Saturday 22nd October 2022)
     is recurring
+
+No grouping instructions supplied.
diff --git a/tests/Query/Explain/DocsSamplesForExplain.test.explain_expands_dates.approved.explanation.text b/tests/Query/Explain/DocsSamplesForExplain.test.explain_expands_dates.approved.explanation.text
index f52200c1..342edf65 100644
--- a/tests/Query/Explain/DocsSamplesForExplain.test.explain_expands_dates.approved.explanation.text
+++ b/tests/Query/Explain/DocsSamplesForExplain.test.explain_expands_dates.approved.explanation.text
@@ -8,3 +8,5 @@ scheduled after 1 week ago =>
 
 due before tomorrow =>
   due date is before 2022-10-22 (Saturday 22nd October 2022)
+
+No grouping instructions supplied.
diff --git a/tests/Query/Explain/DocsSamplesForExplain.test.explain_explains_task_block_with_global_query_active.approved.explanation.text b/tests/Query/Explain/DocsSamplesForExplain.test.explain_explains_task_block_with_global_query_active.approved.explanation.text
index 17c688fb..73fadf55 100644
--- a/tests/Query/Explain/DocsSamplesForExplain.test.explain_explains_task_block_with_global_query_active.approved.explanation.text
+++ b/tests/Query/Explain/DocsSamplesForExplain.test.explain_explains_task_block_with_global_query_active.approved.explanation.text
@@ -2,6 +2,8 @@ Explanation of the global query:
 
 heading includes tasks
 
+No grouping instructions supplied.
+
 
 At most 50 tasks.
 
@@ -13,3 +15,5 @@ due next week =>
   due date is between:
     2022-10-24 (Monday 24th October 2022) and
     2022-10-30 (Sunday 30th October 2022) inclusive
+
+No grouping instructions supplied.
diff --git a/tests/Query/Explain/DocsSamplesForExplain.test.explain_line_continuation_-_double_slash.approved.explanation.text b/tests/Query/Explain/DocsSamplesForExplain.test.explain_line_continuation_-_double_slash.approved.explanation.text
index 70f8ee5a..9ee57de7 100644
--- a/tests/Query/Explain/DocsSamplesForExplain.test.explain_line_continuation_-_double_slash.approved.explanation.text
+++ b/tests/Query/Explain/DocsSamplesForExplain.test.explain_line_continuation_-_double_slash.approved.explanation.text
@@ -1,3 +1,5 @@
 Explanation of this Tasks code block query:
 
 description includes \
+
+No grouping instructions supplied.
diff --git a/tests/Query/Explain/DocsSamplesForExplain.test.explain_line_continuation_-_single_slash.approved.explanation.text b/tests/Query/Explain/DocsSamplesForExplain.test.explain_line_continuation_-_single_slash.approved.explanation.text
index 849113c0..89f6b187 100644
--- a/tests/Query/Explain/DocsSamplesForExplain.test.explain_line_continuation_-_single_slash.approved.explanation.text
+++ b/tests/Query/Explain/DocsSamplesForExplain.test.explain_line_continuation_-_single_slash.approved.explanation.text
@@ -4,3 +4,5 @@ Explanation of this Tasks code block query:
   OR (At least one of):
     priority is highest
     priority is lowest
+
+No grouping instructions supplied.
diff --git a/tests/Query/Explain/DocsSamplesForExplain.test.explain_nested_boolean_combinations.approved.explanation.text b/tests/Query/Explain/DocsSamplesForExplain.test.explain_nested_boolean_combinations.approved.explanation.text
index 28365e62..27b78b58 100644
--- a/tests/Query/Explain/DocsSamplesForExplain.test.explain_nested_boolean_combinations.approved.explanation.text
+++ b/tests/Query/Explain/DocsSamplesForExplain.test.explain_nested_boolean_combinations.approved.explanation.text
@@ -13,3 +13,5 @@ Explanation of this Tasks code block query:
         description includes 7
       NOT:
         description includes 7
+
+No grouping instructions supplied.
diff --git a/tests/Query/Explain/DocsSamplesForExplain.test.explain_placeholders.approved.explanation.text b/tests/Query/Explain/DocsSamplesForExplain.test.explain_placeholders.approved.explanation.text
index ece19863..17a4a87b 100644
--- a/tests/Query/Explain/DocsSamplesForExplain.test.explain_placeholders.approved.explanation.text
+++ b/tests/Query/Explain/DocsSamplesForExplain.test.explain_placeholders.approved.explanation.text
@@ -9,3 +9,5 @@ folder includes some/sample/
 filename includes file path.md
 
 description includes Some Cryptic String 
+
+No grouping instructions supplied.
diff --git a/tests/Query/Explain/DocsSamplesForExplain.test.explain_regular_expression.approved.explanation.text b/tests/Query/Explain/DocsSamplesForExplain.test.explain_regular_expression.approved.explanation.text
index d560785d..c65bc56d 100644
--- a/tests/Query/Explain/DocsSamplesForExplain.test.explain_regular_expression.approved.explanation.text
+++ b/tests/Query/Explain/DocsSamplesForExplain.test.explain_regular_expression.approved.explanation.text
@@ -2,3 +2,5 @@ Explanation of this Tasks code block query:
 
 path regex matches /^Root/Sub-Folder/Sample File\.md/i =>
   using regex:     '^Root\/Sub-Folder\/Sample File\.md' with flag 'i'
+
+No grouping instructions supplied.
diff --git a/tests/Query/Filter/DueDateField.test.ts b/tests/Query/Filter/DueDateField.test.ts
index 87371565..a6b9bc64 100644
--- a/tests/Query/Filter/DueDateField.test.ts
+++ b/tests/Query/Filter/DueDateField.test.ts
@@ -574,7 +574,7 @@ describe('due date', () => {
                 const query = new Query(`due ${keyword}${date}`);
                 expect(query.error).toBeUndefined();
 
-                newRow.push(query.explainQuery().replace(/(\n)/g, '<br>'));
+                newRow.push(query.explainFilters().replace(/(\n)/g, '<br>'));
             });
 
             table.addRow(newRow);
diff --git a/tests/Query/Filter/ReferenceDocs/FilterReference/DateFieldReference.test.explain_date_reference_filters-date-examples.approved.explanation.text b/tests/Query/Filter/ReferenceDocs/FilterReference/DateFieldReference.test.explain_date_reference_filters-date-examples.approved.explanation.text
index a2eada16..f89e7b36 100644
--- a/tests/Query/Filter/ReferenceDocs/FilterReference/DateFieldReference.test.explain_date_reference_filters-date-examples.approved.explanation.text
+++ b/tests/Query/Filter/ReferenceDocs/FilterReference/DateFieldReference.test.explain_date_reference_filters-date-examples.approved.explanation.text
@@ -31,3 +31,5 @@ due 14 October =>
 
 due May =>
   due date is on 2023-05-01 (Monday 1st May 2023)
+
+No grouping instructions supplied.
diff --git a/tests/Query/Filter/ReferenceDocs/FilterReference/DateFieldReference.test.explain_date_reference_last-this-next-week-month-quarter-year.approved.explanation.text b/tests/Query/Filter/ReferenceDocs/FilterReference/DateFieldReference.test.explain_date_reference_last-this-next-week-month-quarter-year.approved.explanation.text
index 55a8a159..1ad89ec7 100644
--- a/tests/Query/Filter/ReferenceDocs/FilterReference/DateFieldReference.test.explain_date_reference_last-this-next-week-month-quarter-year.approved.explanation.text
+++ b/tests/Query/Filter/ReferenceDocs/FilterReference/DateFieldReference.test.explain_date_reference_last-this-next-week-month-quarter-year.approved.explanation.text
@@ -72,3 +72,5 @@ due next year =>
     2024-12-31 (Tuesday 31st December 2024) inclusive
 
 description includes ------------------------------
+
+No grouping instructions supplied.
diff --git a/tests/Query/Filter/ReferenceDocs/FilterReference/DateFieldReference.test.explain_date_reference_last-this-next-weekday.approved.explanation.text b/tests/Query/Filter/ReferenceDocs/FilterReference/DateFieldReference.test.explain_date_reference_last-this-next-weekday.approved.explanation.text
index d22e855f..aecaa07d 100644
--- a/tests/Query/Filter/ReferenceDocs/FilterReference/DateFieldReference.test.explain_date_reference_last-this-next-weekday.approved.explanation.text
+++ b/tests/Query/Filter/ReferenceDocs/FilterReference/DateFieldReference.test.explain_date_reference_last-this-next-weekday.approved.explanation.text
@@ -102,3 +102,5 @@ due next sunday =>
   due date is on 2023-04-23 (Sunday 23rd April 2023)
 
 description includes ------------------------------
+
+No grouping instructions supplied.
diff --git a/tests/Query/Filter/TextField.test.explains_regular_expression_searches_bulk_test.approved.txt b/tests/Query/Filter/TextField.test.explains_regular_expression_searches_bulk_test.approved.txt
index 35a0cc14..b9fd7163 100644
--- a/tests/Query/Filter/TextField.test.explains_regular_expression_searches_bulk_test.approved.txt
+++ b/tests/Query/Filter/TextField.test.explains_regular_expression_searches_bulk_test.approved.txt
@@ -106,4 +106,6 @@ tags regex does not match /(home|town)/ =>
 tags regex matches /(home|pc_mac|town)/ =>
   using regex:     '(home|pc_mac|town)' with no flags
 
+No grouping instructions supplied.
+
 Error: None
diff --git a/tests/TaskGroups.test.ts b/tests/TaskGroups.test.ts
index 5af9cc12..2e323a70 100644
--- a/tests/TaskGroups.test.ts
+++ b/tests/TaskGroups.test.ts
@@ -105,7 +105,7 @@ describe('Grouping tasks', () => {
         const groupByQueryPath: GrouperFunction = (_task: Task, searchInfo: SearchInfo) => {
             return [searchInfo.queryPath ? searchInfo.queryPath : 'No SearchInfo'];
         };
-        const grouper: Grouper = new Grouper('test', groupByQueryPath, false);
+        const grouper: Grouper = new Grouper('group by test', 'test', groupByQueryPath, false);
 
         const filename = 'somewhere/anything.md';
         const tasks = [new TaskBuilder().build()];
@@ -277,7 +277,7 @@ describe('Grouping tasks', () => {
         const inputs = [a, b];
 
         const groupByTags: GrouperFunction = (task: Task) => task.tags;
-        const grouper = new Grouper('custom tag grouper', groupByTags, false);
+        const grouper = new Grouper('group by custom tag grouper', 'custom tag grouper', groupByTags, false);
         const groups = makeTasksGroups([grouper], inputs);
 
         expect(groups.totalTasksCount()).toEqual(2);
diff --git a/tests/lib/QueryRendererHelper.test.ts b/tests/lib/QueryRendererHelper.test.ts
index 9569386b..44813a3d 100644
--- a/tests/lib/QueryRendererHelper.test.ts
+++ b/tests/lib/QueryRendererHelper.test.ts
@@ -16,7 +16,9 @@ describe('explain', () => {
         expect(explainResults(query.source, new GlobalFilter(), new GlobalQuery())).toMatchInlineSnapshot(`
             "Explanation of this Tasks code block query:
 
-            No filters supplied. All tasks will match the query."
+            No filters supplied. All tasks will match the query.
+            No grouping instructions supplied.
+            "
         `);
     });
 
@@ -31,7 +33,9 @@ describe('explain', () => {
 
             Explanation of this Tasks code block query:
 
-            No filters supplied. All tasks will match the query."
+            No filters supplied. All tasks will match the query.
+            No grouping instructions supplied.
+            "
         `);
     });
 
@@ -45,9 +49,13 @@ describe('explain', () => {
 
             description includes hello
 
+            No grouping instructions supplied.
+
             Explanation of this Tasks code block query:
 
-            No filters supplied. All tasks will match the query."
+            No filters supplied. All tasks will match the query.
+            No grouping instructions supplied.
+            "
         `);
     });
 
@@ -65,9 +73,13 @@ describe('explain', () => {
 
             description includes hello
 
+            No grouping instructions supplied.
+
             Explanation of this Tasks code block query:
 
-            No filters supplied. All tasks will match the query."
+            No filters supplied. All tasks will match the query.
+            No grouping instructions supplied.
+            "
         `);
     });
 
@@ -79,7 +91,9 @@ describe('explain', () => {
         expect(explainResults(query.source, new GlobalFilter(), globalQuery)).toMatchInlineSnapshot(`
             "Explanation of this Tasks code block query:
 
-            No filters supplied. All tasks will match the query."
+            No filters supplied. All tasks will match the query.
+            No grouping instructions supplied.
+            "
         `);
     });
 });