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

Issue:
Manual 'double up' arrow doesn't change task priority if followed by Variant Selector
### Please check that this issue hasn't been reported before.

- [X] I searched previous [Bug Reports](https://github.com/obsidian-tasks-group/obsidian-tasks/issues?q=is%3Aopen+is%3Aissue+label%3A%22type%3A+bug%22+sort%3Acomments-desc) didn't find any similar reports.

### Expected Behavior

Appending a double up arrow to the end of a task should give that task a high priority



### Current behaviour

Appending a double up arrow to a task does not change the task priority.

This is an anomoly as:
- appending a single up arrow to a task changes the priority of that task in a list of tasks
- Changing a task to high priority in the task options window appends a double up arrow to a task

BUT ... manually appending a double up arrow to a task does not change the priority of a task in the way that other emojis like the single up arrow does.

### Steps to reproduce

Create task with double up arrow manually appended to the end of a task
Create a dataview listing of that task
check the priority assigned

### Which Operating Systems are you using?

- [ ] Android
- [ ] iPhone/iPad
- [ ] Linux
- [X] macOS
- [ ] Windows

### Obsidian Version

1.4.13

### Tasks Plugin Version

0.1.16

### Checks

- [ ] I have tried it with all other plugins disabled and the error still occurs

### Possible solution

_No response_

Pull request description:
Fix priority with vs16
<!--- Provide a general summary of your changes in the Title above -->

# Description

Fix parsing of Priority emoji with Variant Selector 16 appended.

## Motivation and Context


Fixes #2273.

## How has this been tested?

- New tests, initially failing.
- Manual exploratory testing - confirming I could reproduce the problem behaviour before the fix, and that it was then behaving correctly afterwards.

## Screenshots (if appropriate)

None.

## 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] **Bug fix** (prefix: `fix` - non-breaking change which fixes an issue)

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`.
- [ ] My change requires a change to the documentation.
- [ ] 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/src/TaskSerializer/DefaultTaskSerializer.ts b/src/TaskSerializer/DefaultTaskSerializer.ts
index e8087bb3..584f76ce 100644
--- a/src/TaskSerializer/DefaultTaskSerializer.ts
+++ b/src/TaskSerializer/DefaultTaskSerializer.ts
@@ -74,7 +74,8 @@ export const DEFAULT_SYMBOLS: DefaultTaskSerializerSymbols = {
     TaskFormatRegularExpressions: {
         // The following regex's end with `$` because they will be matched and
         // removed from the end until none are left.
-        priorityRegex: /([🔺⏫🔼🔽⏬])$/u,
+        // \uFE0F? allows an optional Variant Selector 16 on emojis.
+        priorityRegex: /([🔺⏫🔼🔽⏬])\uFE0F?$/u,
         startDateRegex: /🛫 *(\d{4}-\d{2}-\d{2})$/u,
         createdDateRegex: /➕ *(\d{4}-\d{2}-\d{2})$/u,
         scheduledDateRegex: /[⏳⌛] *(\d{4}-\d{2}-\d{2})$/u,


Test patch:
diff --git a/tests/TaskSerializer/DefaultTaskSerializer.test.ts b/tests/TaskSerializer/DefaultTaskSerializer.test.ts
index b9a558b4..e8cdc85c 100644
--- a/tests/TaskSerializer/DefaultTaskSerializer.test.ts
+++ b/tests/TaskSerializer/DefaultTaskSerializer.test.ts
@@ -19,6 +19,17 @@ type DefaultTaskSerializeSymbolMap = readonly {
 // A map that facilitates parameterizing the tests over symbols
 const symbolMap: DefaultTaskSerializeSymbolMap = [{ taskFormat: 'tasksPluginEmoji', symbols: DEFAULT_SYMBOLS }];
 
+/**
+ * Since Variant Selectors are invisible, any tests whose behaviour is dependent on the
+ * presence or absence of one MUST 'expect' on the result of this function,
+ * to confirm that the test is doing what it claims to be doing.
+ * @param text
+ */
+function hasVariantSelector16(text: string) {
+    const vs16Regex = /\uFE0F/u;
+    return text.match(vs16Regex) !== null;
+}
+
 // NEW_TASK_FIELD_EDIT_REQUIRED
 
 describe.each(symbolMap)("DefaultTaskSerializer with '$taskFormat' symbols", ({ symbols }) => {
@@ -67,6 +78,23 @@ describe.each(symbolMap)("DefaultTaskSerializer with '$taskFormat' symbols", ({
                     expect(taskDetails).toMatchTaskDetails({ priority });
                 }
             });
+
+            it('should parse a high priority without Variant Selector 16', () => {
+                const line = '⏫';
+                expect(hasVariantSelector16(line)).toBe(false);
+
+                const taskDetails = deserialize(line);
+                expect(taskDetails).toMatchTaskDetails({ priority: Priority.High });
+            });
+
+            it('should parse a high priority with Variant Selector 16', () => {
+                // This test showed the existing of https://github.com/obsidian-tasks-group/obsidian-tasks/issues/2273
+                const line = '⏫️'; // There is a hidden Variant Selector 16 character at the end of this string
+                expect(hasVariantSelector16(line)).toBe(true);
+
+                const taskDetails = deserialize(line);
+                expect(taskDetails).toMatchTaskDetails({ priority: Priority.High });
+            });
         });
 
         it('should parse a recurrence', () => {