Repository: obsidian-tasks-group/obsidian-tasks
Pull request #2425 (2023-11-20 09:02:44)

refactor: add a container for `FieldLayoutDetails` and get data attributes from it
# Description

Add a container for `FieldLayoutDetails` and get data attributes from it with a dedicated method.

## Motivation and Context

Encapsulate data and behaviour in an error-free way.

Prepare for refactoring of the rendering & layout code to make adding new features easier.

## How has this been tested?

Unit tests added for the new class.

## Types of 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

- [x] My code follows the code style of this project and passes `yarn run lint`.
- [x] My change has adequate [Unit Test coverage](https://publish.obsidian.md/tasks-contributing/Testing/About+Testing).

## Terms

- [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/TaskLineRenderer.ts b/src/TaskLineRenderer.ts
index 709c88fd..5a4f396e 100644
--- a/src/TaskLineRenderer.ts
+++ b/src/TaskLineRenderer.ts
@@ -21,6 +21,29 @@ export type TaskLineRenderDetails = {
 
 type AttributeValueCalculator = (component: TaskLayoutComponent, task: Task) => string;
 
+export class FieldLayoutsContainer {
+    private details = FieldLayoutDetails;
+
+    constructor() {}
+
+    /**
+     * Searches for the component among the {@link FieldLayoutDetails} and gets its data attribute
+     * in a given task. The data attribute shall be added in the task's `<span>`.
+     * For example, a task with medium priority and done yesterday will have
+     * `data-task-priority="medium" data-task-due="past-1d" ` in its data attributes.
+     *
+     * If the data attribute is absent in the task, an empty {@link AttributesDictionary} is returned.
+     *
+     * For detailed calculation see {@link FieldLayoutDetail.dataAttribute}.
+     *
+     * @param component the component of the task for which the data attribute has to be generated.
+     * @param task the task from which the data shall be taken
+     */
+    public dataAttribute(component: TaskLayoutComponent, task: Task) {
+        return this.details[component].dataAttribute(component, task);
+    }
+}
+
 export class FieldLayoutDetail {
     readonly className: string;
     readonly attributeName: string;
@@ -56,6 +79,8 @@ export class FieldLayoutDetail {
     }
 
     /**
+     * Shall be called only by {@link FieldLayoutsContainer}. Use that class if you need the data attributes.
+     *
      * @returns the data attribute, associated to with a task's component, added in the task's `<span>`.
      * For example, a task with medium priority and done yesterday will have
      * `data-task-priority="medium" data-task-due="past-1d" ` in its data attributes.
@@ -65,7 +90,7 @@ export class FieldLayoutDetail {
      * @param component the component of the task for which the data attribute has to be generated.
      * @param task the task from which the data shall be taken
      */
-    public getDataAttribute(component: TaskLayoutComponent, task: Task) {
+    public dataAttribute(component: TaskLayoutComponent, task: Task) {
         const dataAttribute: AttributesDictionary = {};
 
         if (this.attributeName !== FieldLayoutDetail.noAttributeName) {
@@ -88,7 +113,7 @@ const dateDataAttributeCalculator: AttributeValueCalculator = (component: TaskLa
     return '';
 };
 
-export const FieldLayouts: { [c in TaskLayoutComponent]: FieldLayoutDetail } = {
+export const FieldLayoutDetails: { [c in TaskLayoutComponent]: FieldLayoutDetail } = {
     createdDate: new FieldLayoutDetail('task-created', 'taskCreated', dateDataAttributeCalculator),
     dueDate: new FieldLayoutDetail('task-due', 'taskDue', dateDataAttributeCalculator),
     startDate: new FieldLayoutDetail('task-start', 'taskStart', dateDataAttributeCalculator),
@@ -117,6 +142,8 @@ export const FieldLayouts: { [c in TaskLayoutComponent]: FieldLayoutDetail } = {
     ),
 };
 
+const FieldLayouts = new FieldLayoutsContainer();
+
 const MAX_DAY_VALUE_RANGE = 7;
 const DAY_VALUE_OVER_RANGE_POSTFIX = 'far';
 
@@ -239,14 +266,14 @@ async function taskToHtml(
                 addInternalClasses(component, internalSpan);
 
                 // Add the component's CSS class describing what this component is (priority, due date etc.)
-                const fieldLayoutDetails = FieldLayouts[component];
+                const fieldLayoutDetails = FieldLayoutDetails[component];
                 if (fieldLayoutDetails) {
                     const componentClass = [fieldLayoutDetails.className];
                     span.classList.add(...componentClass);
                 }
 
                 // Add the component's attribute ('priority-medium', 'due-past-1d' etc.)
-                const componentDataAttribute = FieldLayouts[component].getDataAttribute(component, task);
+                const componentDataAttribute = FieldLayouts.dataAttribute(component, task);
                 for (const key in componentDataAttribute) span.dataset[key] = componentDataAttribute[key];
                 allAttributes = { ...allAttributes, ...componentDataAttribute };
             }
@@ -255,7 +282,7 @@ async function taskToHtml(
 
     // Now build classes for the hidden task components without rendering them
     for (const component of taskLayout.hiddenTaskLayoutComponents) {
-        const hiddenComponentDataAttribute = FieldLayouts[component].getDataAttribute(component, task);
+        const hiddenComponentDataAttribute = FieldLayouts.dataAttribute(component, task);
         allAttributes = { ...allAttributes, ...hiddenComponentDataAttribute };
     }
 
@@ -265,7 +292,7 @@ async function taskToHtml(
     // So if the priority was not rendered, force it through the pipe of getting the component data for the
     // priority field.
     if (allAttributes.taskPriority === undefined) {
-        const priorityDataAttribute = FieldLayouts['priority'].getDataAttribute('priority', task);
+        const priorityDataAttribute = FieldLayouts.dataAttribute('priority', task);
         allAttributes = { ...allAttributes, ...priorityDataAttribute };
     }
 


Test patch:
diff --git a/tests/TaskLineRenderer.test.ts b/tests/TaskLineRenderer.test.ts
index ede72d6d..03e10dad 100644
--- a/tests/TaskLineRenderer.test.ts
+++ b/tests/TaskLineRenderer.test.ts
@@ -10,7 +10,7 @@ import type { Task } from '../src/Task';
 import { TaskRegularExpressions } from '../src/Task';
 import { LayoutOptions } from '../src/TaskLayout';
 import type { AttributesDictionary, TextRenderer } from '../src/TaskLineRenderer';
-import { FieldLayoutDetail, FieldLayouts, renderTaskLine } from '../src/TaskLineRenderer';
+import { FieldLayoutDetail, FieldLayoutDetails, FieldLayoutsContainer, renderTaskLine } from '../src/TaskLineRenderer';
 import { fromLine } from './TestHelpers';
 import { verifyWithFileExtension } from './TestingTools/ApprovalTestHelpers';
 import { TaskBuilder } from './TestingTools/TaskBuilder';
@@ -59,7 +59,7 @@ function getOtherLayoutComponents(parentElement: HTMLElement): string[] {
     const textSpan = getTextSpan(parentElement);
     const components: string[] = [];
     for (const childSpan of Array.from(textSpan.children)) {
-        if (childSpan.classList.contains(FieldLayouts.description.className)) continue;
+        if (childSpan.classList.contains(FieldLayoutDetails.description.className)) continue;
         if (childSpan?.textContent) components.push(childSpan.textContent);
     }
     return components;
@@ -352,19 +352,19 @@ describe('task line rendering', () => {
         await testComponentClasses(
             '- [ ] Full task ⏫ 📅 2022-07-02 ⏳ 2022-07-03 🛫 2022-07-04 🔁 every day',
             {},
-            FieldLayouts.priority.className,
+            FieldLayoutDetails.priority.className,
             { taskPriority: 'high' },
         );
         await testComponentClasses(
             '- [ ] Full task 🔼 📅 2022-07-02 ⏳ 2022-07-03 🛫 2022-07-04 🔁 every day',
             {},
-            FieldLayouts.priority.className,
+            FieldLayoutDetails.priority.className,
             { taskPriority: 'medium' },
         );
         await testComponentClasses(
             '- [ ] Full task 🔽 📅 2022-07-02 ⏳ 2022-07-03 🛫 2022-07-04 🔁 every day',
             {},
-            FieldLayouts.priority.className,
+            FieldLayoutDetails.priority.className,
             { taskPriority: 'low' },
         );
     });
@@ -373,174 +373,174 @@ describe('task line rendering', () => {
         await testComponentClasses(
             '- [ ] Full task ⏫ 📅 2022-07-02 ⏳ 2022-07-03 🛫 2022-07-04 🔁 every day',
             {},
-            FieldLayouts.recurrenceRule.className,
+            FieldLayoutDetails.recurrenceRule.className,
             {},
         );
     });
 
     it('adds a correct "today" CSS class to dates', async () => {
         const today = DateParser.parseDate('today').format(TaskRegularExpressions.dateFormat);
-        await testComponentClasses(`- [ ] Full task ⏫ ➕ ${today}`, {}, FieldLayouts.createdDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ ➕ ${today}`, {}, FieldLayoutDetails.createdDate.className, {
             taskCreated: 'today',
         });
-        await testComponentClasses(`- [ ] Full task ⏫ 📅 ${today}`, {}, FieldLayouts.dueDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ 📅 ${today}`, {}, FieldLayoutDetails.dueDate.className, {
             taskDue: 'today',
         });
-        await testComponentClasses(`- [ ] Full task ⏫ ⏳ ${today}`, {}, FieldLayouts.scheduledDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ ⏳ ${today}`, {}, FieldLayoutDetails.scheduledDate.className, {
             taskScheduled: 'today',
         });
-        await testComponentClasses(`- [ ] Full task ⏫ 🛫 ${today}`, {}, FieldLayouts.startDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ 🛫 ${today}`, {}, FieldLayoutDetails.startDate.className, {
             taskStart: 'today',
         });
-        await testComponentClasses(`- [x] Done task ✅ ${today}`, {}, FieldLayouts.doneDate.className, {
+        await testComponentClasses(`- [x] Done task ✅ ${today}`, {}, FieldLayoutDetails.doneDate.className, {
             taskDone: 'today',
         });
     });
 
     it('adds a correct "future-1d" CSS class to dates', async () => {
         const future = DateParser.parseDate('tomorrow').format(TaskRegularExpressions.dateFormat);
-        await testComponentClasses(`- [ ] Full task ⏫ ➕ ${future}`, {}, FieldLayouts.createdDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ ➕ ${future}`, {}, FieldLayoutDetails.createdDate.className, {
             taskCreated: 'future-1d',
         });
-        await testComponentClasses(`- [ ] Full task ⏫ 📅 ${future}`, {}, FieldLayouts.dueDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ 📅 ${future}`, {}, FieldLayoutDetails.dueDate.className, {
             taskDue: 'future-1d',
         });
-        await testComponentClasses(`- [ ] Full task ⏫ ⏳ ${future}`, {}, FieldLayouts.scheduledDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ ⏳ ${future}`, {}, FieldLayoutDetails.scheduledDate.className, {
             taskScheduled: 'future-1d',
         });
-        await testComponentClasses(`- [ ] Full task ⏫ 🛫 ${future}`, {}, FieldLayouts.startDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ 🛫 ${future}`, {}, FieldLayoutDetails.startDate.className, {
             taskStart: 'future-1d',
         });
-        await testComponentClasses(`- [x] Done task ✅ ${future}`, {}, FieldLayouts.doneDate.className, {
+        await testComponentClasses(`- [x] Done task ✅ ${future}`, {}, FieldLayoutDetails.doneDate.className, {
             taskDone: 'future-1d',
         });
     });
 
     it('adds a correct "future-7d" CSS class to dates', async () => {
         const future = DateParser.parseDate('in 7 days').format(TaskRegularExpressions.dateFormat);
-        await testComponentClasses(`- [ ] Full task ⏫ ➕ ${future}`, {}, FieldLayouts.createdDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ ➕ ${future}`, {}, FieldLayoutDetails.createdDate.className, {
             taskCreated: 'future-7d',
         });
-        await testComponentClasses(`- [ ] Full task ⏫ 📅 ${future}`, {}, FieldLayouts.dueDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ 📅 ${future}`, {}, FieldLayoutDetails.dueDate.className, {
             taskDue: 'future-7d',
         });
-        await testComponentClasses(`- [ ] Full task ⏫ ⏳ ${future}`, {}, FieldLayouts.scheduledDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ ⏳ ${future}`, {}, FieldLayoutDetails.scheduledDate.className, {
             taskScheduled: 'future-7d',
         });
-        await testComponentClasses(`- [ ] Full task ⏫ 🛫 ${future}`, {}, FieldLayouts.startDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ 🛫 ${future}`, {}, FieldLayoutDetails.startDate.className, {
             taskStart: 'future-7d',
         });
-        await testComponentClasses(`- [x] Done task ✅ ${future}`, {}, FieldLayouts.doneDate.className, {
+        await testComponentClasses(`- [x] Done task ✅ ${future}`, {}, FieldLayoutDetails.doneDate.className, {
             taskDone: 'future-7d',
         });
     });
 
     it('adds a correct "past-1d" CSS class to dates', async () => {
         const past = DateParser.parseDate('yesterday').format(TaskRegularExpressions.dateFormat);
-        await testComponentClasses(`- [ ] Full task ⏫ ➕ ${past}`, {}, FieldLayouts.createdDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ ➕ ${past}`, {}, FieldLayoutDetails.createdDate.className, {
             taskCreated: 'past-1d',
         });
-        await testComponentClasses(`- [ ] Full task ⏫ 📅 ${past}`, {}, FieldLayouts.dueDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ 📅 ${past}`, {}, FieldLayoutDetails.dueDate.className, {
             taskDue: 'past-1d',
         });
-        await testComponentClasses(`- [ ] Full task ⏫ ⏳ ${past}`, {}, FieldLayouts.scheduledDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ ⏳ ${past}`, {}, FieldLayoutDetails.scheduledDate.className, {
             taskScheduled: 'past-1d',
         });
-        await testComponentClasses(`- [ ] Full task ⏫ 🛫 ${past}`, {}, FieldLayouts.startDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ 🛫 ${past}`, {}, FieldLayoutDetails.startDate.className, {
             taskStart: 'past-1d',
         });
-        await testComponentClasses(`- [x] Done task ✅ ${past}`, {}, FieldLayouts.doneDate.className, {
+        await testComponentClasses(`- [x] Done task ✅ ${past}`, {}, FieldLayoutDetails.doneDate.className, {
             taskDone: 'past-1d',
         });
     });
 
     it('adds a correct "past-7d" CSS class to dates', async () => {
         const past = DateParser.parseDate('7 days ago').format(TaskRegularExpressions.dateFormat);
-        await testComponentClasses(`- [ ] Full task ⏫ ➕ ${past}`, {}, FieldLayouts.createdDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ ➕ ${past}`, {}, FieldLayoutDetails.createdDate.className, {
             taskCreated: 'past-7d',
         });
-        await testComponentClasses(`- [ ] Full task ⏫ 📅 ${past}`, {}, FieldLayouts.dueDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ 📅 ${past}`, {}, FieldLayoutDetails.dueDate.className, {
             taskDue: 'past-7d',
         });
-        await testComponentClasses(`- [ ] Full task ⏫ ⏳ ${past}`, {}, FieldLayouts.scheduledDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ ⏳ ${past}`, {}, FieldLayoutDetails.scheduledDate.className, {
             taskScheduled: 'past-7d',
         });
-        await testComponentClasses(`- [ ] Full task ⏫ 🛫 ${past}`, {}, FieldLayouts.startDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ 🛫 ${past}`, {}, FieldLayoutDetails.startDate.className, {
             taskStart: 'past-7d',
         });
-        await testComponentClasses(`- [x] Done task ✅ ${past}`, {}, FieldLayouts.doneDate.className, {
+        await testComponentClasses(`- [x] Done task ✅ ${past}`, {}, FieldLayoutDetails.doneDate.className, {
             taskDone: 'past-7d',
         });
     });
 
     it('adds the classes "...future-far" and "...past-far" to dates that are further than 7 days', async () => {
         const future = DateParser.parseDate('in 8 days').format(TaskRegularExpressions.dateFormat);
-        await testComponentClasses(`- [ ] Full task ⏫ ➕ ${future}`, {}, FieldLayouts.createdDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ ➕ ${future}`, {}, FieldLayoutDetails.createdDate.className, {
             taskCreated: 'future-far',
         });
-        await testComponentClasses(`- [ ] Full task ⏫ 📅 ${future}`, {}, FieldLayouts.dueDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ 📅 ${future}`, {}, FieldLayoutDetails.dueDate.className, {
             taskDue: 'future-far',
         });
-        await testComponentClasses(`- [ ] Full task ⏫ ⏳ ${future}`, {}, FieldLayouts.scheduledDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ ⏳ ${future}`, {}, FieldLayoutDetails.scheduledDate.className, {
             taskScheduled: 'future-far',
         });
-        await testComponentClasses(`- [ ] Full task ⏫ 🛫 ${future}`, {}, FieldLayouts.startDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ 🛫 ${future}`, {}, FieldLayoutDetails.startDate.className, {
             taskStart: 'future-far',
         });
-        await testComponentClasses(`- [x] Done task ✅ ${future}`, {}, FieldLayouts.doneDate.className, {
+        await testComponentClasses(`- [x] Done task ✅ ${future}`, {}, FieldLayoutDetails.doneDate.className, {
             taskDone: 'future-far',
         });
         const past = DateParser.parseDate('8 days ago').format(TaskRegularExpressions.dateFormat);
-        await testComponentClasses(`- [ ] Full task ⏫ ➕ ${past}`, {}, FieldLayouts.createdDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ ➕ ${past}`, {}, FieldLayoutDetails.createdDate.className, {
             taskCreated: 'past-far',
         });
-        await testComponentClasses(`- [ ] Full task ⏫ 📅 ${past}`, {}, FieldLayouts.dueDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ 📅 ${past}`, {}, FieldLayoutDetails.dueDate.className, {
             taskDue: 'past-far',
         });
-        await testComponentClasses(`- [ ] Full task ⏫ ⏳ ${past}`, {}, FieldLayouts.scheduledDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ ⏳ ${past}`, {}, FieldLayoutDetails.scheduledDate.className, {
             taskScheduled: 'past-far',
         });
-        await testComponentClasses(`- [ ] Full task ⏫ 🛫 ${past}`, {}, FieldLayouts.startDate.className, {
+        await testComponentClasses(`- [ ] Full task ⏫ 🛫 ${past}`, {}, FieldLayoutDetails.startDate.className, {
             taskStart: 'past-far',
         });
-        await testComponentClasses(`- [x] Done task ✅ ${past}`, {}, FieldLayouts.doneDate.className, {
+        await testComponentClasses(`- [x] Done task ✅ ${past}`, {}, FieldLayoutDetails.doneDate.className, {
             taskDone: 'past-far',
         });
     });
 
     it('does not add specific classes to invalid dates', async () => {
-        await testComponentClasses('- [ ] Full task ⏫ 📅 2023-02-29', {}, FieldLayouts.dueDate.className, {});
+        await testComponentClasses('- [ ] Full task ⏫ 📅 2023-02-29', {}, FieldLayoutDetails.dueDate.className, {});
     });
 
     it('does not render hidden components but sets their specific classes to the upper li element', async () => {
         await testHiddenComponentClasses(
             '- [ ] Full task ⏫ 📅 2022-07-02 ⏳ 2022-07-03 🛫 2022-07-04 🔁 every day',
             { hidePriority: true },
-            FieldLayouts.priority.className,
+            FieldLayoutDetails.priority.className,
             { taskPriority: 'high' },
         );
         await testHiddenComponentClasses(
             '- [ ] Full task ⏫ 📅 2022-07-02 ⏳ 2022-07-03 ➕ 2022-07-04 🔁 every day',
             { hideCreatedDate: true },
-            FieldLayouts.createdDate.className,
+            FieldLayoutDetails.createdDate.className,
             { taskCreated: 'past-far' },
         );
         await testHiddenComponentClasses(
             '- [ ] Full task ⏫ 📅 2022-07-02 ⏳ 2022-07-03 🛫 2022-07-04 🔁 every day',
             { hideDueDate: true },
-            FieldLayouts.dueDate.className,
+            FieldLayoutDetails.dueDate.className,
             { taskDue: 'past-far' },
         );
         await testHiddenComponentClasses(
             '- [ ] Full task ⏫ 📅 2022-07-02 ⏳ 2022-07-03 🛫 2022-07-04 🔁 every day',
             { hideScheduledDate: true },
-            FieldLayouts.scheduledDate.className,
+            FieldLayoutDetails.scheduledDate.className,
             { taskScheduled: 'past-far' },
         );
         await testHiddenComponentClasses(
             '- [ ] Full task ⏫ 📅 2022-07-02 ⏳ 2022-07-03 🛫 2022-07-04 🔁 every day',
             { hideStartDate: true },
-            FieldLayouts.startDate.className,
+            FieldLayoutDetails.startDate.className,
             { taskStart: 'past-far' },
         );
     });
@@ -678,6 +678,46 @@ ${task.toFileLineString()}
     });
 });
 
+describe('Field Layouts Container tests', () => {
+    beforeEach(() => {
+        jest.useFakeTimers();
+        jest.setSystemTime(new Date('2023-11-19'));
+    });
+
+    afterEach(() => {
+        jest.useRealTimers();
+    });
+
+    it('should get the data attribute of an existing component (date)', () => {
+        const container = new FieldLayoutsContainer();
+        const task = new TaskBuilder().dueDate('2023-11-20').build();
+
+        const dueDateDataAttribute = container.dataAttribute('dueDate', task);
+
+        expect(Object.keys(dueDateDataAttribute).length).toEqual(1);
+        expect(dueDateDataAttribute['taskDue']).toEqual('future-1d');
+    });
+
+    it('should get the data attribute of an existing component (not date)', () => {
+        const container = new FieldLayoutsContainer();
+        const task = TaskBuilder.createFullyPopulatedTask();
+
+        const dueDateDataAttribute = container.dataAttribute('priority', task);
+
+        expect(Object.keys(dueDateDataAttribute).length).toEqual(1);
+        expect(dueDateDataAttribute['taskPriority']).toEqual('medium');
+    });
+
+    it('should return empty data attributes dictionary for a missing component', () => {
+        const container = new FieldLayoutsContainer();
+        const task = new TaskBuilder().build();
+
+        const dueDateDataAttribute = container.dataAttribute('recurrenceRule', task);
+
+        expect(Object.keys(dueDateDataAttribute).length).toEqual(0);
+    });
+});
+
 describe('Field Layout Detail tests', () => {
     it('should supply a class name and a data attribute name', () => {
         const fieldLayoutDetail = new FieldLayoutDetail('stuff', 'taskAttribute', () => {
@@ -699,7 +739,7 @@ describe('Field Layout Detail tests', () => {
         const fieldLayoutDetail = new FieldLayoutDetail('dataAttributeTest', 'aKey', () => {
             return 'aValue';
         });
-        const dataAttribute = fieldLayoutDetail.getDataAttribute('description', new TaskBuilder().build());
+        const dataAttribute = fieldLayoutDetail.dataAttribute('description', new TaskBuilder().build());
 
         expect(Object.keys(dataAttribute).length).toEqual(1);
         expect(dataAttribute['aKey']).toEqual('aValue');