Repository: obsidian-tasks-group/obsidian-tasks
Pull request #2351 (2023-10-20 17:08:18)

docs: Mermaid status diagrams now machine-generated
<!--- Provide a general summary of your changes in the Title above -->

# Description

- Write and test code to generate Mermaid diagrams that represent the transitions between statuses in Tasks settings
- Update the 'Example Statuses' page to use these machine-generated diagrams.

Note: One diagram is now a different orientation. It's now consistent with all the others.

## Motivation and Context

1. Ensure that the diagrams are correct.
2. Make it easier to add new examples.
3. It's a small step on the way to allowing users to visualise the statuses in their own settings.

## How has this been tested?

By viewing the generated diagrams in Obsidian.

## Screenshots (if appropriate)

## 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] **Documentation** (prefix: `docs` - improvements to any documentation content **for users**)

Internal changes:

- [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/Getting Started/Statuses/Example Statuses.md b/docs/Getting Started/Statuses/Example Statuses.md
index 35ac8088..50d7841c 100644
--- a/docs/Getting Started/Statuses/Example Statuses.md
+++ b/docs/Getting Started/Statuses/Example Statuses.md
@@ -16,10 +16,17 @@ You can tweak Tasks' `Todo` status so that it toggles to 'In Progress', which th
 
 This might be useful if you have a few slightly more time-consuming tasks to keep an eye on. Perhaps you would like to prioritise finishing things that are in progress before starting something new?
 
+<!-- include: DocsSamplesForStatuses.test.DefaultStatuses_todo-in_progress-done.approved.mermaid.md -->
 ```mermaid
 flowchart LR
-1[Todo] --> 2[In Progress] --> 3[Done] --> 1
+1[Todo]
+2[In Progress]
+3[Done]
+1 --> 2
+2 --> 3
+3 --> 1
 ```
+<!-- endInclude -->
 
 <!-- placeholder to force blank line before included text --><!-- include: DocsSamplesForStatuses.test.DefaultStatuses_todo-in_progress-done.approved.md -->
 
@@ -37,10 +44,17 @@ Sometimes I have a few really important tasks that I wish to stand out from the
 
 By using non-standard symbols for the `IN_PROGRESS` and `DONE` statuses, if I decide to later re-open one of these completed tasks, it automatically goes on to `!` again.
 
+<!-- include: DocsSamplesForStatuses.test.DefaultStatuses_important-cycle.approved.mermaid.md -->
 ```mermaid
 flowchart LR
-1[Important] --> 2[Doing - Important] --> 3[Done - Important] --> 1
+1[Important]
+2[Doing - Important]
+3[Done - Important]
+1 --> 2
+2 --> 3
+3 --> 1
 ```
+<!-- endInclude -->
 
 <!-- placeholder to force blank line before included text --><!-- include: DocsSamplesForStatuses.test.DefaultStatuses_important-cycle.approved.md -->
 
@@ -60,10 +74,15 @@ Happily, some themes use `P` and `C` for these. Others use `p` and `c`.
 
 Either way, I can make them toggle to each other, and by giving them the type `NON_TASK`, I can exclude them from my Tasks searches, as I don't see them as actionable.
 
+<!-- include: DocsSamplesForStatuses.test.DefaultStatuses_pro-con-cycle.approved.mermaid.md -->
 ```mermaid
 flowchart LR
-1[Pro] --> 2[Con] --> 1
+1[Pro]
+2[Con]
+1 --> 2
+2 --> 1
 ```
+<!-- endInclude -->
 
 <!-- placeholder to force blank line before included text --><!-- include: DocsSamplesForStatuses.test.DefaultStatuses_pro-con-cycle.approved.md -->
 
@@ -82,14 +101,21 @@ There is a nice property that statuses with the same Status Symbol and Next Stat
 
 Here are some statuses from the ITS Theme where this behaviour might be useful.
 
+<!-- include: DocsSamplesForStatuses.test.DefaultStatuses_toggle-does-nothing.approved.mermaid.md -->
 ```mermaid
-flowchart TD
-1[Bookmark] --> 1
-2[Example] --> 2
-3[Information] --> 3
-4[Paraphrase] --> 4
-5[Quote] --> 5
+flowchart LR
+1[Bookmark]
+2[Example]
+3[Information]
+4[Paraphrase]
+5[Quote]
+1 --> 1
+2 --> 2
+3 --> 3
+4 --> 4
+5 --> 5
 ```
+<!-- endInclude -->
 
 <!-- placeholder to force blank line before included text --><!-- include: DocsSamplesForStatuses.test.DefaultStatuses_toggle-does-nothing.approved.md -->
 
diff --git a/src/StatusRegistry.ts b/src/StatusRegistry.ts
index 3492cf12..041bcf07 100644
--- a/src/StatusRegistry.ts
+++ b/src/StatusRegistry.ts
@@ -35,6 +35,19 @@ export class StatusRegistry {
         this.addDefaultStatusTypes();
     }
 
+    /**
+     * Reset this instance to contain only the given status list, in the supplied order.
+     *
+     * Duplicate status symbols are ignored.
+     * @param statuses
+     */
+    public set(statuses: StatusConfiguration[] | Status[]) {
+        this.clearStatuses();
+        statuses.forEach((status) => {
+            this.add(status);
+        });
+    }
+
     /**
      * Returns all the registered statuses minus the empty status.
      *
@@ -273,4 +286,42 @@ export class StatusRegistry {
             this.add(status);
         });
     }
+
+    /**
+     * Create a Mermaid diagram from the statuses in this registry.
+     *
+     * The text can be pasted in to an Obsidian note to visualise the transitions between
+     * statuses.
+     *
+     * Note: Any of the 'next status symbols' that are not in the registry are ignored, and invisble.
+     */
+    public mermaidDiagram() {
+        const uniqueStatuses = this.registeredStatuses;
+
+        const language = 'mermaid';
+
+        const nodes: string[] = [];
+        const edges: string[] = [];
+        uniqueStatuses.forEach((status, index) => {
+            nodes.push(`${index + 1}[${status.name}]`);
+
+            // Check the next status:
+            const nextStatus = this.getNextStatus(status);
+            const nextStatusIndex = uniqueStatuses.findIndex((status) => status.symbol === nextStatus.symbol);
+            const nextStatusIsKnown = nextStatusIndex !== -1;
+            const nextStatusIsNotInternal = nextStatus.type !== StatusType.EMPTY;
+
+            if (nextStatusIsKnown && nextStatusIsNotInternal) {
+                edges.push(`${index + 1} --> ${nextStatusIndex + 1}`);
+            }
+        });
+
+        return `
+\`\`\`${language}
+flowchart LR
+${nodes.join('\n')}
+${edges.join('\n')}
+\`\`\`
+`;
+    }
 }


Test patch:
diff --git a/tests/DocumentationSamples/DocsSamplesForStatuses.test.DefaultStatuses_core-statuses.approved.mermaid.md b/tests/DocumentationSamples/DocsSamplesForStatuses.test.DefaultStatuses_core-statuses.approved.mermaid.md
new file mode 100644
index 00000000..8974e778
--- /dev/null
+++ b/tests/DocumentationSamples/DocsSamplesForStatuses.test.DefaultStatuses_core-statuses.approved.mermaid.md
@@ -0,0 +1,8 @@
+
+```mermaid
+flowchart LR
+1[Todo]
+2[Done]
+1 --> 2
+2 --> 1
+```
diff --git a/tests/DocumentationSamples/DocsSamplesForStatuses.test.DefaultStatuses_custom-statuses.approved.mermaid.md b/tests/DocumentationSamples/DocsSamplesForStatuses.test.DefaultStatuses_custom-statuses.approved.mermaid.md
new file mode 100644
index 00000000..d7f767c1
--- /dev/null
+++ b/tests/DocumentationSamples/DocsSamplesForStatuses.test.DefaultStatuses_custom-statuses.approved.mermaid.md
@@ -0,0 +1,7 @@
+
+```mermaid
+flowchart LR
+1[In Progress]
+2[Cancelled]
+
+```
diff --git a/tests/DocumentationSamples/DocsSamplesForStatuses.test.DefaultStatuses_important-cycle.approved.mermaid.md b/tests/DocumentationSamples/DocsSamplesForStatuses.test.DefaultStatuses_important-cycle.approved.mermaid.md
new file mode 100644
index 00000000..e74daf81
--- /dev/null
+++ b/tests/DocumentationSamples/DocsSamplesForStatuses.test.DefaultStatuses_important-cycle.approved.mermaid.md
@@ -0,0 +1,10 @@
+
+```mermaid
+flowchart LR
+1[Important]
+2[Doing - Important]
+3[Done - Important]
+1 --> 2
+2 --> 3
+3 --> 1
+```
diff --git a/tests/DocumentationSamples/DocsSamplesForStatuses.test.DefaultStatuses_pro-con-cycle.approved.mermaid.md b/tests/DocumentationSamples/DocsSamplesForStatuses.test.DefaultStatuses_pro-con-cycle.approved.mermaid.md
new file mode 100644
index 00000000..43cf3f0a
--- /dev/null
+++ b/tests/DocumentationSamples/DocsSamplesForStatuses.test.DefaultStatuses_pro-con-cycle.approved.mermaid.md
@@ -0,0 +1,8 @@
+
+```mermaid
+flowchart LR
+1[Pro]
+2[Con]
+1 --> 2
+2 --> 1
+```
diff --git a/tests/DocumentationSamples/DocsSamplesForStatuses.test.DefaultStatuses_todo-in_progress-done.approved.mermaid.md b/tests/DocumentationSamples/DocsSamplesForStatuses.test.DefaultStatuses_todo-in_progress-done.approved.mermaid.md
new file mode 100644
index 00000000..8bd6f89b
--- /dev/null
+++ b/tests/DocumentationSamples/DocsSamplesForStatuses.test.DefaultStatuses_todo-in_progress-done.approved.mermaid.md
@@ -0,0 +1,10 @@
+
+```mermaid
+flowchart LR
+1[Todo]
+2[In Progress]
+3[Done]
+1 --> 2
+2 --> 3
+3 --> 1
+```
diff --git a/tests/DocumentationSamples/DocsSamplesForStatuses.test.DefaultStatuses_toggle-does-nothing.approved.mermaid.md b/tests/DocumentationSamples/DocsSamplesForStatuses.test.DefaultStatuses_toggle-does-nothing.approved.mermaid.md
new file mode 100644
index 00000000..4fc5a0fb
--- /dev/null
+++ b/tests/DocumentationSamples/DocsSamplesForStatuses.test.DefaultStatuses_toggle-does-nothing.approved.mermaid.md
@@ -0,0 +1,14 @@
+
+```mermaid
+flowchart LR
+1[Bookmark]
+2[Example]
+3[Information]
+4[Paraphrase]
+5[Quote]
+1 --> 1
+2 --> 2
+3 --> 3
+4 --> 4
+5 --> 5
+```
diff --git a/tests/DocumentationSamples/DocsSamplesForStatuses.test.Theme_AnuPpuccin_Table.approved.mermaid.md b/tests/DocumentationSamples/DocsSamplesForStatuses.test.Theme_AnuPpuccin_Table.approved.mermaid.md
new file mode 100644
index 00000000..4c02b8d0
--- /dev/null
+++ b/tests/DocumentationSamples/DocsSamplesForStatuses.test.Theme_AnuPpuccin_Table.approved.mermaid.md
@@ -0,0 +1,60 @@
+
+```mermaid
+flowchart LR
+1[Unchecked]
+2[Checked]
+3[Rescheduled]
+4[Scheduled]
+5[Important]
+6[Cancelled]
+7[In Progress]
+8[Question]
+9[Star]
+10[Note]
+11[Location]
+12[Information]
+13[Idea]
+14[Amount]
+15[Pro]
+16[Con]
+17[Bookmark]
+18[Quote]
+19[Speech bubble 0]
+20[Speech bubble 1]
+21[Speech bubble 2]
+22[Speech bubble 3]
+23[Speech bubble 4]
+24[Speech bubble 5]
+25[Speech bubble 6]
+26[Speech bubble 7]
+27[Speech bubble 8]
+28[Speech bubble 9]
+1 --> 2
+2 --> 1
+3 --> 2
+4 --> 2
+5 --> 2
+6 --> 1
+7 --> 2
+8 --> 2
+9 --> 2
+10 --> 2
+11 --> 2
+12 --> 2
+13 --> 2
+14 --> 2
+15 --> 2
+16 --> 2
+17 --> 2
+18 --> 2
+19 --> 19
+20 --> 20
+21 --> 21
+22 --> 22
+23 --> 23
+24 --> 24
+25 --> 25
+26 --> 26
+27 --> 27
+28 --> 28
+```
diff --git a/tests/DocumentationSamples/DocsSamplesForStatuses.test.Theme_Aura_Table.approved.mermaid.md b/tests/DocumentationSamples/DocsSamplesForStatuses.test.Theme_Aura_Table.approved.mermaid.md
new file mode 100644
index 00000000..f8ca4e78
--- /dev/null
+++ b/tests/DocumentationSamples/DocsSamplesForStatuses.test.Theme_Aura_Table.approved.mermaid.md
@@ -0,0 +1,42 @@
+
+```mermaid
+flowchart LR
+1[incomplete]
+2[complete / done]
+3[cancelled]
+4[deferred]
+5[in progress, or half-done]
+6[Important]
+7[question]
+8[review]
+9[Inbox / task that should be processed later]
+10[bookmark]
+11[brainstorm]
+12[deferred or scheduled]
+13[Info]
+14[idea]
+15[note]
+16[quote]
+17[win / success / reward]
+18[pro]
+19[con]
+1 --> 2
+2 --> 1
+3 --> 1
+4 --> 2
+5 --> 2
+6 --> 2
+7 --> 2
+8 --> 2
+9 --> 2
+10 --> 2
+11 --> 2
+12 --> 2
+13 --> 2
+14 --> 2
+15 --> 2
+16 --> 2
+17 --> 2
+18 --> 2
+19 --> 2
+```
diff --git a/tests/DocumentationSamples/DocsSamplesForStatuses.test.Theme_Ebullientworks_Table.approved.mermaid.md b/tests/DocumentationSamples/DocsSamplesForStatuses.test.Theme_Ebullientworks_Table.approved.mermaid.md
new file mode 100644
index 00000000..0d8ba1ac
--- /dev/null
+++ b/tests/DocumentationSamples/DocsSamplesForStatuses.test.Theme_Ebullientworks_Table.approved.mermaid.md
@@ -0,0 +1,20 @@
+
+```mermaid
+flowchart LR
+1[Unchecked]
+2[Checked]
+3[Cancelled]
+4[In Progress]
+5[Deferred]
+6[Important]
+7[Question]
+8[Review]
+1 --> 2
+2 --> 1
+3 --> 1
+4 --> 2
+5 --> 2
+6 --> 2
+7 --> 2
+8 --> 2
+```
diff --git a/tests/DocumentationSamples/DocsSamplesForStatuses.test.Theme_ITS_Table.approved.mermaid.md b/tests/DocumentationSamples/DocsSamplesForStatuses.test.Theme_ITS_Table.approved.mermaid.md
new file mode 100644
index 00000000..2fb248bb
--- /dev/null
+++ b/tests/DocumentationSamples/DocsSamplesForStatuses.test.Theme_ITS_Table.approved.mermaid.md
@@ -0,0 +1,78 @@
+
+```mermaid
+flowchart LR
+1[Unchecked]
+2[Regular]
+3[Checked]
+4[Dropped]
+5[Forward]
+6[Date]
+7[Question]
+8[Half Done]
+9[Add]
+10[Research]
+11[Important]
+12[Idea]
+13[Brainstorm]
+14[Pro]
+15[Con]
+16[Quote]
+17[Note]
+18[Bookmark]
+19[Information]
+20[Paraphrase]
+21[Location]
+22[Example]
+23[Answer]
+24[Reward]
+25[Choice]
+26[Doing]
+27[Time]
+28[Character / Person]
+29[Talk]
+30[Outline / Plot]
+31[Conflict]
+32[World]
+33[Clue / Find]
+34[Foreshadow]
+35[Favorite / Health]
+36[Symbolism]
+37[Secret]
+1 --> 2
+2 --> 1
+3 --> 1
+4 --> 1
+5 --> 2
+6 --> 2
+7 --> 2
+8 --> 2
+9 --> 2
+10 --> 2
+11 --> 2
+12 --> 2
+13 --> 2
+14 --> 2
+15 --> 2
+16 --> 2
+17 --> 2
+18 --> 2
+19 --> 2
+20 --> 2
+21 --> 2
+22 --> 2
+23 --> 2
+24 --> 2
+25 --> 2
+26 --> 2
+27 --> 2
+28 --> 2
+29 --> 2
+30 --> 2
+31 --> 2
+32 --> 2
+33 --> 2
+34 --> 2
+35 --> 2
+36 --> 2
+37 --> 2
+```
diff --git a/tests/DocumentationSamples/DocsSamplesForStatuses.test.Theme_LYT_Mode_Table.approved.mermaid.md b/tests/DocumentationSamples/DocsSamplesForStatuses.test.Theme_LYT_Mode_Table.approved.mermaid.md
new file mode 100644
index 00000000..921eba9c
--- /dev/null
+++ b/tests/DocumentationSamples/DocsSamplesForStatuses.test.Theme_LYT_Mode_Table.approved.mermaid.md
@@ -0,0 +1,48 @@
+
+```mermaid
+flowchart LR
+1[Unchecked]
+2[Checked]
+3[Rescheduled]
+4[Scheduled]
+5[Important]
+6[Cancelled]
+7[In Progress]
+8[Question]
+9[Star]
+10[Note]
+11[Location]
+12[Information]
+13[Idea]
+14[Amount]
+15[Pro]
+16[Con]
+17[Bookmark]
+18[Fire]
+19[Key]
+20[Win]
+21[Up]
+22[Down]
+1 --> 2
+2 --> 1
+3 --> 2
+4 --> 2
+5 --> 2
+6 --> 1
+7 --> 2
+8 --> 2
+9 --> 2
+10 --> 2
+11 --> 2
+12 --> 2
+13 --> 2
+14 --> 2
+15 --> 2
+16 --> 2
+17 --> 2
+18 --> 2
+19 --> 2
+20 --> 2
+21 --> 2
+22 --> 2
+```
diff --git a/tests/DocumentationSamples/DocsSamplesForStatuses.test.Theme_Minimal_Table.approved.mermaid.md b/tests/DocumentationSamples/DocsSamplesForStatuses.test.Theme_Minimal_Table.approved.mermaid.md
new file mode 100644
index 00000000..634931ae
--- /dev/null
+++ b/tests/DocumentationSamples/DocsSamplesForStatuses.test.Theme_Minimal_Table.approved.mermaid.md
@@ -0,0 +1,48 @@
+
+```mermaid
+flowchart LR
+1[to-do]
+2[incomplete]
+3[done]
+4[canceled]
+5[forwarded]
+6[scheduling]
+7[question]
+8[important]
+9[star]
+10[quote]
+11[location]
+12[bookmark]
+13[information]
+14[savings]
+15[idea]
+16[pros]
+17[cons]
+18[fire]
+19[key]
+20[win]
+21[up]
+22[down]
+1 --> 3
+2 --> 3
+3 --> 1
+4 --> 1
+5 --> 3
+6 --> 3
+7 --> 3
+8 --> 3
+9 --> 3
+10 --> 3
+11 --> 3
+12 --> 3
+13 --> 3
+14 --> 3
+15 --> 3
+16 --> 3
+17 --> 3
+18 --> 3
+19 --> 3
+20 --> 3
+21 --> 3
+22 --> 3
+```
diff --git a/tests/DocumentationSamples/DocsSamplesForStatuses.test.Theme_Things_Table.approved.mermaid.md b/tests/DocumentationSamples/DocsSamplesForStatuses.test.Theme_Things_Table.approved.mermaid.md
new file mode 100644
index 00000000..634931ae
--- /dev/null
+++ b/tests/DocumentationSamples/DocsSamplesForStatuses.test.Theme_Things_Table.approved.mermaid.md
@@ -0,0 +1,48 @@
+
+```mermaid
+flowchart LR
+1[to-do]
+2[incomplete]
+3[done]
+4[canceled]
+5[forwarded]
+6[scheduling]
+7[question]
+8[important]
+9[star]
+10[quote]
+11[location]
+12[bookmark]
+13[information]
+14[savings]
+15[idea]
+16[pros]
+17[cons]
+18[fire]
+19[key]
+20[win]
+21[up]
+22[down]
+1 --> 3
+2 --> 3
+3 --> 1
+4 --> 1
+5 --> 3
+6 --> 3
+7 --> 3
+8 --> 3
+9 --> 3
+10 --> 3
+11 --> 3
+12 --> 3
+13 --> 3
+14 --> 3
+15 --> 3
+16 --> 3
+17 --> 3
+18 --> 3
+19 --> 3
+20 --> 3
+21 --> 3
+22 --> 3
+```
diff --git a/tests/DocumentationSamples/DocsSamplesForStatuses.test.ts b/tests/DocumentationSamples/DocsSamplesForStatuses.test.ts
index 4a33a978..ac2c75e9 100644
--- a/tests/DocumentationSamples/DocsSamplesForStatuses.test.ts
+++ b/tests/DocumentationSamples/DocsSamplesForStatuses.test.ts
@@ -13,6 +13,8 @@ import * as Themes from '../../src/Config/Themes';
 import { StatusValidator } from '../../src/StatusValidator';
 import { TaskBuilder } from '../TestingTools/TaskBuilder';
 import { MarkdownTable, verifyMarkdownForDocs } from '../TestingTools/VerifyMarkdownTable';
+import { StatusRegistry } from '../../src/StatusRegistry';
+import { verifyWithFileExtension } from '../TestingTools/ApprovalTestHelpers';
 
 function getPrintableSymbol(symbol: string) {
     const result = symbol !== ' ' ? symbol : 'space';
@@ -70,19 +72,29 @@ function constructStatuses(importedStatuses: StatusCollection) {
     return statuses;
 }
 
+function verifyStatusesInMultipleFormats(statuses: Status[], showQueryInstructions: boolean) {
+    verifyStatusesAsMarkdownTable(statuses, showQueryInstructions);
+    verifyStatusesAsMermaidDiagram(statuses);
+}
+
+function verifyStatusesAsMermaidDiagram(statuses: Status[]) {
+    // Set the registry up to exactly match the supplied statuses
+    const registry = new StatusRegistry();
+    registry.set(statuses);
+
+    const markdown = registry.mermaidDiagram();
+    verifyWithFileExtension(markdown, 'mermaid.md');
+}
+
 describe('DefaultStatuses', () => {
     // These "test" write out a markdown representation of the default task statuses,
     // for embedding in the user docs.
-    // TODO There are hand-created Mermaid diagrams of some of this in 'Example Statuses'.
-    //      If ever the statuses are changed here, or new examples added, spend a few
-    //      minutes to write out the Mermaid diagrams automatically, and embed the
-    //      generated mermaid files inside the docs, replacing the hand-crafted ones.
     it('core-statuses', () => {
-        verifyStatusesAsMarkdownTable([Status.makeTodo(), Status.makeDone()], true);
+        verifyStatusesInMultipleFormats([Status.makeTodo(), Status.makeDone()], true);
     });
 
     it('custom-statuses', () => {
-        verifyStatusesAsMarkdownTable([Status.makeInProgress(), Status.makeCancelled()], true);
+        verifyStatusesInMultipleFormats([Status.makeInProgress(), Status.makeCancelled()], true);
     });
 
     it('important-cycle', () => {
@@ -91,7 +103,7 @@ describe('DefaultStatuses', () => {
             ['D', 'Doing - Important', 'X', 'IN_PROGRESS'],
             ['X', 'Done - Important', '!', 'DONE'],
         ];
-        verifyStatusesAsMarkdownTable(constructStatuses(importantCycle), false);
+        verifyStatusesInMultipleFormats(constructStatuses(importantCycle), false);
     });
 
     it('todo-in_progress-done', () => {
@@ -100,7 +112,7 @@ describe('DefaultStatuses', () => {
             ['/', 'In Progress', 'x', 'IN_PROGRESS'],
             ['x', 'Done', ' ', 'DONE'],
         ];
-        verifyStatusesAsMarkdownTable(constructStatuses(importantCycle), false);
+        verifyStatusesInMultipleFormats(constructStatuses(importantCycle), false);
     });
 
     it('pro-con-cycle', () => {
@@ -108,7 +120,7 @@ describe('DefaultStatuses', () => {
             ['P', 'Pro', 'C', 'NON_TASK'],
             ['C', 'Con', 'P', 'NON_TASK'],
         ];
-        verifyStatusesAsMarkdownTable(constructStatuses(importantCycle), false);
+        verifyStatusesInMultipleFormats(constructStatuses(importantCycle), false);
     });
 
     it('toggle-does-nothing', () => {
@@ -119,7 +131,7 @@ describe('DefaultStatuses', () => {
             ['P', 'Paraphrase', 'P', 'NON_TASK'],
             ['Q', 'Quote', 'Q', 'NON_TASK'],
         ];
-        verifyStatusesAsMarkdownTable(constructStatuses(importantCycle), false);
+        verifyStatusesInMultipleFormats(constructStatuses(importantCycle), false);
     });
 });
 
@@ -144,7 +156,7 @@ describe('Theme', () => {
         });
 
         it('Table', () => {
-            verifyStatusesAsMarkdownTable(constructStatuses(statuses), true);
+            verifyStatusesInMultipleFormats(constructStatuses(statuses), true);
         });
 
         it('Tasks', () => {
diff --git a/tests/StatusRegistry.test.ts b/tests/StatusRegistry.test.ts
index 250b21bd..9c4f72cf 100644
--- a/tests/StatusRegistry.test.ts
+++ b/tests/StatusRegistry.test.ts
@@ -58,6 +58,23 @@ describe('StatusRegistry', () => {
         expect(statusRegistry.registeredStatuses.length).toEqual(0);
     });
 
+    it('should allow setting the entire set of statuses', () => {
+        // Arrange
+        const statusRegistry = new StatusRegistry();
+        const statuses = [
+            new StatusConfiguration('Q', 'Question', 'A', false, StatusType.NON_TASK),
+            new StatusConfiguration('A', 'Answer', 'Q', false, StatusType.NON_TASK),
+        ];
+
+        // Act
+        statusRegistry.set(statuses);
+
+        // Assert
+        expect(statusRegistry.registeredStatuses.length).toEqual(2);
+        expect(statusRegistry.registeredStatuses[0].symbol).toStrictEqual('Q');
+        expect(statusRegistry.registeredStatuses[1].symbol).toStrictEqual('A');
+    });
+
     it('should return empty status for lookup by unknown symbol with bySymbol()', () => {
         // Arrange
         const statusRegistry = new StatusRegistry();
@@ -146,6 +163,55 @@ describe('StatusRegistry', () => {
         expect(status2).toStrictEqual(status);
     });
 
+    it('should create a mermaid diagram of default statuses', () => {
+        // Arrange
+        const statusRegistry = new StatusRegistry();
+
+        // Act
+        const mermaidText = statusRegistry.mermaidDiagram();
+
+        // Assert
+        expect(mermaidText).toMatchInlineSnapshot(`
+            "
+            \`\`\`mermaid
+            flowchart LR
+            1[Todo]
+            2[In Progress]
+            3[Done]
+            4[Cancelled]
+            1 --> 3
+            2 --> 3
+            3 --> 1
+            4 --> 1
+            \`\`\`
+            "
+        `);
+    });
+
+    it('should not include unknown nextStatusSymbols in mermaid diagrams', () => {
+        // Arrange
+        const statusRegistry = new StatusRegistry();
+        statusRegistry.clearStatuses();
+        statusRegistry.add(new StatusConfiguration(' ', 'Todo', '/', false, StatusType.TODO));
+        // Leave '/' as not registered
+        const originalNumberOfStatuses = statusRegistry.registeredStatuses.length;
+
+        // Act
+        const mermaidText = statusRegistry.mermaidDiagram();
+
+        // Assert
+        expect(statusRegistry.registeredStatuses.length).toEqual(originalNumberOfStatuses);
+        expect(mermaidText).toMatchInlineSnapshot(`
+            "
+            \`\`\`mermaid
+            flowchart LR
+            1[Todo]
+
+            \`\`\`
+            "
+        `);
+    });
+
     describe('toggling', () => {
         it('should allow task to toggle through standard transitions', () => {
             // Arrange