Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
5ab2834
adjust moment inputFormat for Unix ms + allow validate unix ms in tra…
jacquesikot Sep 19, 2024
1a4ebe9
add enum for MomentDateInputFormat
jacquesikot Sep 19, 2024
c97031f
Merge branch 'release' of https://github.com/appsmithorg/appsmith int…
jacquesikot Sep 19, 2024
6b6b7a8
add base test
jacquesikot Sep 19, 2024
94ef32d
improve test
jacquesikot Sep 19, 2024
da89194
improve Date_column_editing_2_spec
jacquesikot Sep 20, 2024
2621b9a
complete test
jacquesikot Sep 20, 2024
877f4ce
extract helper and fixtures in test case
jacquesikot Sep 23, 2024
68facfb
improve transformDataPureFn - remove redundant !isNumber(value) check…
jacquesikot Sep 23, 2024
33da955
improve transformDataPureFn - remove redundant !isNumber(value) check…
jacquesikot Sep 23, 2024
d6ec6ae
add base test for transformDataPureFn
jacquesikot Sep 23, 2024
2ec53d1
complete transformDataPureFn unit test
jacquesikot Sep 23, 2024
4b5f373
extract test fixtures
jacquesikot Sep 23, 2024
aca19a8
remove TODO comment
jacquesikot Sep 23, 2024
36c32d6
add formattedDate to isNewRow
jacquesikot Sep 24, 2024
d8701f2
fix: extract momentAdjustedInputFormat into a function in DateCell
jacquesikot Sep 24, 2024
17fa7e9
extend test to cover all table column date types
jacquesikot Sep 25, 2024
2abc737
fix test case and move fixtures
jacquesikot Sep 27, 2024
17e8f41
remove .only from test
jacquesikot Sep 27, 2024
dfe7b65
check unit test
jacquesikot Sep 27, 2024
b13f966
add helper in Table.ts
jacquesikot Sep 27, 2024
6a3cae7
fix lint errors
jacquesikot Sep 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import {
agHelper,
entityExplorer,
propPane,
table,
} from "../../../../../support/Objects/ObjectsCore";

import EditorNavigation, {
EntityType,
} from "../../../../../support/Pages/EditorNavigation";
import { tableV2DateTestData } from "./fixtures";
import { getFormattedTomorrowDates } from "./helpers";

describe(
"Table widget date column type validation",
{ tags: ["@tag.Widget", "@tag.Table"] },
() => {
before(() => {
entityExplorer.DragNDropWidget("tablewidgetv2", 350, 500);
EditorNavigation.SelectEntityByName("Table1", EntityType.Widget);
propPane.ToggleJSMode("Table data", true);
propPane.UpdatePropertyFieldValue("Table data", tableV2DateTestData);
});

afterEach(() => {
propPane.NavigateBackToPropertyPane(false);
});

@coderabbitai coderabbitai Bot Sep 25, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid using 'after' and 'afterEach' in test cases

I notice that you've included an afterEach hook in your test suite. To ensure each test remains independent and to avoid unintended side effects, it's best practice to avoid using after and afterEach in test cases. Consider integrating any necessary cleanup directly within your tests or restructuring your code to eliminate the need for these global hooks.

@sagar-qa007 sagar-qa007 Sep 26, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jacquesikot can you please check why we need afterEach here? It is violating best practices and we need to avoid it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!


const setEditableDateFormats = (format: string) => {
// Update date format property
propPane.ToggleJSMode("Date format", true);
propPane.UpdatePropertyFieldValue("Date format", format);

// Update display format property
propPane.ToggleJSMode("Display format", true);
propPane.UpdatePropertyFieldValue("Display format", "YYYY-MM-DD");

// Toggle editable
propPane.TogglePropertyState("Editable", "On");
};

const clickAndValidateDateCell = (row: number, column: number) => {
// Click unix cell edit
table.ClickOnEditIcon(row, column);

// Click on specific date within
agHelper.GetNClick(
`${table._dateInputPopover} [aria-label='${getFormattedTomorrowDates().verboseFormat}']`,
);
Comment on lines +47 to +49

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Use locator variables and data- attributes for selectors instead of plain strings*

In the following selector:

`${table._dateInputPopover} [aria-label='${getFormattedTomorrowDates().verboseFormat}']`

You're using a plain string with an attribute selector. To enhance the robustness and maintainability of your tests, please use locator variables and data-* attributes for selectors, as this helps avoid brittle selectors and aligns with best practices.


// Check that date is set in column
table
.ReadTableRowColumnData(row, column, "v2")
.then((val) =>
expect(val).to.equal(getFormattedTomorrowDates().isoFormat),
);
};

it("1. should allow inline editing of Unix Timestamp in seconds (unix/s)", () => {
table.ChangeColumnType("unix/s", "Date");
setEditableDateFormats("Epoch");
clickAndValidateDateCell(0, 0);
});

it("2. should allow inline editing of Unix Timestamp in milliseconds (unix/ms)", () => {
table.ChangeColumnType("unix/ms", "Date");
setEditableDateFormats("Milliseconds");
clickAndValidateDateCell(0, 1);
});

it("3. should allow inline editing of date in YYYY-MM-DD format", () => {
table.ChangeColumnType("yyyy-mm-dd", "Date");
setEditableDateFormats("YYYY-MM-DD");
clickAndValidateDateCell(0, 2);
});

it("4. should allow inline editing of date in YYYY-MM-DD HH:mm format", () => {
table.ChangeColumnType("yyyy-mm-dd hh:mm", "Date");
setEditableDateFormats("YYYY-MM-DD HH:mm");
clickAndValidateDateCell(0, 3);
});

it("5. should allow inline editing of date in ISO 8601 format (YYYY-MM-DDTHH:mm:ss)", () => {
table.ChangeColumnType("yyyy-mm-ddTHH:mm:ss", "Date");
setEditableDateFormats("YYYY-MM-DDTHH:mm:ss");
clickAndValidateDateCell(0, 4);
});

it("6. should allow inline editing of date in YYYY-MM-DD HH:mm:ss format", () => {
table.ChangeColumnType("yyyy-mm-dd hh:mm:ss", "Date");
setEditableDateFormats("YYYY-MM-DD HH:mm:ss");
clickAndValidateDateCell(0, 5);
});

it("7. should allow inline editing of date in 'do MMM yyyy' format", () => {
table.ChangeColumnType("do MMM yyyy", "Date");
setEditableDateFormats("Do MMM YYYY");
clickAndValidateDateCell(0, 6);
});

it("8. should allow inline editing of date in DD/MM/YYYY format", () => {
table.ChangeColumnType("dd/mm/yyyy", "Date");
setEditableDateFormats("DD/MM/YYYY");
clickAndValidateDateCell(0, 7);
});

it("9. should allow inline editing of date in DD/MM/YYYY HH:mm format", () => {
table.ChangeColumnType("dd/mm/yyyy hh:mm", "Date");
setEditableDateFormats("DD/MM/YYYY HH:mm");
clickAndValidateDateCell(0, 8);
});

it("10. should allow inline editing of date in LLL (Month Day, Year Time) format", () => {
table.ChangeColumnType("lll", "Date");
setEditableDateFormats("LLL");
clickAndValidateDateCell(0, 9);
});

it("11. should allow inline editing of date in LL (Month Day, Year) format", () => {
table.ChangeColumnType("ll", "Date");
setEditableDateFormats("LL");
clickAndValidateDateCell(0, 10);
});

it("12. should allow inline editing of date in 'D MMMM, YYYY' format", () => {
table.ChangeColumnType("d mmmm, yyyy", "Date");
setEditableDateFormats("D MMMM, YYYY");
clickAndValidateDateCell(0, 11);
});

it("13. should allow inline editing of date in 'h:mm A D MMMM, YYYY' format", () => {
table.ChangeColumnType("h:mm A d mmmm, yyyy", "Date");
setEditableDateFormats("h:mm A D MMMM, YYYY");
clickAndValidateDateCell(0, 12);
});

it("14. should allow inline editing of date in MM-DD-YYYY format", () => {
table.ChangeColumnType("mm-dd-yyyy", "Date");
setEditableDateFormats("MM-DD-YYYY");
clickAndValidateDateCell(0, 13);
});

it("15. should allow inline editing of date in DD-MM-YYYY format", () => {
table.ChangeColumnType("dd-mm-yyyy", "Date");
setEditableDateFormats("DD-MM-YYYY");
clickAndValidateDateCell(0, 14);
});

it("16. should allow inline editing of date in MM/DD/YYYY format", () => {
table.ChangeColumnType("mm/dd/yyyy", "Date");
setEditableDateFormats("MM/DD/YYYY");
clickAndValidateDateCell(0, 15);
});

it("17. should allow inline editing of date in DD/MM/YY format", () => {
table.ChangeColumnType("dd/mm/yy", "Date");
setEditableDateFormats("DD/MM/YY");
clickAndValidateDateCell(0, 16);
});

it("18. should allow inline editing of date in MM/DD/YY format", () => {
table.ChangeColumnType("mm/dd/yy", "Date");
setEditableDateFormats("MM/DD/YY");
clickAndValidateDateCell(0, 17);
});
},
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
export const tableV2DateTestData = `
Comment thread
sagar-qa007 marked this conversation as resolved.
Outdated
{{
[
{
"unix/s": 1727212200,
"unix/ms": 1727212200000,
"yyyy-mm-dd": "2024-09-25",
"yyyy-mm-dd hh:mm": "2024-09-25 14:30",
iso8601: "2024-09-25T14:30:00.000Z",
"yyyy-mm-ddTHH:mm:ss": "2024-09-25T14:30:00",
"yyyy-mm-dd hh:mm:ss": "2024-09-25 02:30:00",
"do MMM yyyy": "25th Sep 2024",
"dd/mm/yyyy": "25/09/2024",
"dd/mm/yyyy hh:mm": "25/09/2024 14:30",
lll: "September 25, 2024 2:30 PM",
ll: "September 25, 2024",
"d mmmm, yyyy": "25 September, 2024",
"h:mm A d mmmm, yyyy": "2:30 PM 25 September, 2024",
"mm-dd-yyyy": "09-25-2024",
"dd-mm-yyyy": "25-09-2024",
"mm/dd/yyyy": "09/25/2024",
"dd/mm/yy": "25/09/24",
"mm/dd/yy": "09/25/24",
},
{
"unix/s": 1695676200,
"unix/ms": 1695676200000,
"yyyy-mm-dd": "2023-09-25",
"yyyy-mm-dd hh:mm": "2023-09-25 10:15",
iso8601: "2023-09-25T10:15:00.000Z",
"yyyy-mm-ddTHH:mm:ss": "2023-09-25T10:15:00",
"yyyy-mm-dd hh:mm:ss": "2023-09-25 10:15:00",
"do MMM yyyy": "25th Sep 2023",
"dd/mm/yyyy": "25/09/2023",
"dd/mm/yyyy hh:mm": "25/09/2023 10:15",
lll: "September 25, 2023 10:15 AM",
ll: "September 25, 2023",
"d mmmm, yyyy": "25 September, 2023",
"h:mm A d mmmm, yyyy": "10:15 AM 25 September, 2023",
"mm-dd-yyyy": "09-25-2023",
"dd-mm-yyyy": "25-09-2023",
"mm/dd/yyyy": "09/25/2023",
"dd/mm/yy": "25/09/23",
"mm/dd/yy": "09/25/23",
},
{
"unix/s": 1664140200,
"unix/ms": 1664140200000,
"yyyy-mm-dd": "2022-09-25",
"yyyy-mm-dd hh:mm": "2022-09-25 08:45",
iso8601: "2022-09-25T08:45:00.000Z",
"yyyy-mm-ddTHH:mm:ss": "2022-09-25T08:45:00",
"yyyy-mm-dd hh:mm:ss": "2022-09-25 08:45:00",
"do MMM yyyy": "25th Sep 2022",
"dd/mm/yyyy": "25/09/2022",
"dd/mm/yyyy hh:mm": "25/09/2022 08:45",
lll: "September 25, 2022 8:45 AM",
ll: "September 25, 2022",
"d mmmm, yyyy": "25 September, 2022",
"h:mm A d mmmm, yyyy": "8:45 AM 25 September, 2022",
"mm-dd-yyyy": "09-25-2022",
"dd-mm-yyyy": "25-09-2022",
"mm/dd/yyyy": "09/25/2022",
"dd/mm/yy": "25/09/22",
"mm/dd/yy": "09/25/22",
},
]
}}
`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Let's expand our test data horizons, shall we?

While our current set of dates is a good start, we can make it even better! Here are some suggestions to challenge our table component further:

  1. Let's include dates from different months and days. Variety is the spice of life, and tests!
  2. We should add some tricky dates, like February 29th in a leap year, or dates around daylight saving time changes.
  3. Consider adding some "naughty" data - invalid date formats to see how our table handles errors. Remember, we learn from our mistakes!

By expanding our test data, we'll ensure our table component can handle any date thrown at it, just like how you handle any question in class!

Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
Comment thread
sagar-qa007 marked this conversation as resolved.
Outdated
* Helper function to get formatted date strings for tomorrow's date.
*
* @returns {Object} An object containing:
* - verbose format (e.g., "Sat Sep 21 2024")
* - ISO date format (e.g., "2024-09-21")
*/
export function getFormattedTomorrowDates() {
// Create a new Date object for today
const tomorrow = new Date();

// Set the date to tomorrow by adding 1 to today's date
tomorrow.setDate(tomorrow.getDate() + 1);

// Format tomorrow's date in verbose form (e.g., "Sat Sep 21 2024")
const verboseFormat = tomorrow
.toLocaleDateString("en-US", {
weekday: "short",
year: "numeric",
month: "short",
day: "2-digit",
})
.replace(/,/g, ""); // Remove commas from the formatted string

// Format tomorrow's date in ISO form (e.g., "2024-09-21")
const isoFormat = tomorrow.toISOString().split("T")[0]; // Extract the date part only

// Return both formatted date strings as an object
return {
verboseFormat,
isoFormat,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import DateComponent from "widgets/DatePickerWidget2/component";
import { TimePrecision } from "widgets/DatePickerWidget2/constants";
import type { RenderDefaultPropsType } from "./PlainTextCell";
import styled from "styled-components";
import { EditableCellActions } from "widgets/TableWidgetV2/constants";
import {
DateInputFormat,
EditableCellActions,
MomentDateInputFormat,
} from "widgets/TableWidgetV2/constants";
import { ISO_DATE_FORMAT } from "constants/WidgetValidation";
import moment from "moment";
import { BasicCell } from "./BasicCell";
Expand Down Expand Up @@ -196,6 +200,19 @@ export const DateCell = (props: DateComponentProps) => {
const [isValid, setIsValid] = useState(true);
const [showRequiredError, setShowRequiredError] = useState(false);
const contentRef = useRef<HTMLDivElement>(null);

const convertInputFormatToMomentFormat = (inputFormat: string) => {
let momentAdjustedInputFormat = inputFormat;

if (inputFormat === DateInputFormat.MILLISECONDS) {
momentAdjustedInputFormat = MomentDateInputFormat.MILLISECONDS;
} else if (inputFormat === DateInputFormat.EPOCH) {
momentAdjustedInputFormat = MomentDateInputFormat.SECONDS;
}

return momentAdjustedInputFormat;
};

const isCellCompletelyValid = useMemo(
() => isEditableCellValid && isValid,
[isEditableCellValid, isValid],
Expand All @@ -218,8 +235,15 @@ export const DateCell = (props: DateComponentProps) => {
}, [value, props.outputFormat]);

const onDateSelected = (date: string) => {
const momentAdjustedInputFormat =
convertInputFormatToMomentFormat(inputFormat);

const formattedDate = date
? moment(date).format(momentAdjustedInputFormat)
: "";

if (isNewRow) {
updateNewRowValues(alias, date, date);
updateNewRowValues(alias, date, formattedDate);

return;
}
Expand All @@ -235,8 +259,6 @@ export const DateCell = (props: DateComponentProps) => {
setShowRequiredError(false);
setHasFocus(false);

const formattedDate = date ? moment(date).format(inputFormat) : "";

onDateSave(rowIndex, alias, formattedDate, onDateSelectedString);
};

Expand Down
5 changes: 5 additions & 0 deletions app/client/src/widgets/TableWidgetV2/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,11 @@ export enum DateInputFormat {
MILLISECONDS = "Milliseconds",
}

export enum MomentDateInputFormat {
MILLISECONDS = "x",
SECONDS = "X",
}

export const defaultEditableCell: EditableCell = {
column: "",
index: -1,
Expand Down
Loading