Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,7 @@
"expensifyneue",
"expensifynewkansas",
"expensifyreactnative",
"exportedto",
"fabs",
"falso",
"favicons",
Expand Down Expand Up @@ -900,6 +901,7 @@
"symbolspacer",
"systempreferences",
"tabindex",
"taxrate",
"teachersunite",
"testflight",
"textanchor",
Expand All @@ -910,6 +912,7 @@
"tickvalues",
"tnode",
"tobe",
"toggleable",
"togglefullscreen",
"tosorted",
"touchables",
Expand Down
118 changes: 63 additions & 55 deletions src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6641,43 +6641,65 @@ const CONST = {
YEAR: 'year',
QUARTER: 'quarter',
},
/**
* Single source of truth for which transaction-level columns are available in each column-picker surface:
* - `search`: the Spend/Search picker (`/search` → Display → Edit columns), read via `TYPE_CUSTOM_COLUMNS.EXPENSE`.
* - `reportView`: the single-report picker (`r/:reportID/settings/columns`), read via `REPORT_DETAILS_CUSTOM_COLUMNS`.
*
* Both `TYPE_CUSTOM_COLUMNS.EXPENSE` and `REPORT_DETAILS_CUSTOM_COLUMNS` are derived from this map (preserving
* this declaration order), so adding a new column forces a single, deliberate availability decision here instead
* of silently drifting between two hand-maintained lists. A guard test (`tests/unit/Search/ColumnAvailabilityTest.ts`)
* asserts every expense-relevant `TABLE_COLUMNS` value is classified here or explicitly owned by another surface.
*
* Rule of thumb for `reportView`: a column belongs in the single-report view only if its value can differ between
* expenses within the same report. Report-level values (identical on every row) stay Search-only.
*/
get COLUMN_AVAILABILITY() {
return {
RECEIPT: {column: this.TABLE_COLUMNS.RECEIPT, search: true, reportView: true},
DATE: {column: this.TABLE_COLUMNS.DATE, search: true, reportView: true},
STATUS: {column: this.TABLE_COLUMNS.STATUS, search: true, reportView: false},
SUBMITTED: {column: this.TABLE_COLUMNS.SUBMITTED, search: true, reportView: false},
APPROVED: {column: this.TABLE_COLUMNS.APPROVED, search: true, reportView: false},
POSTED: {column: this.TABLE_COLUMNS.POSTED, search: true, reportView: true},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep newly exposed report columns renderable

When Posted is added to REPORT_DETAILS_CUSTOM_COLUMNS, the report column settings page lets users save it, but MoneyRequestReportTransactionList still calls getColumnsToShow(..., isExpenseReportView: true), whose custom-column path filters the saved list down to nonDataColumns.has(col) || columns[col]. POSTED is never set in the report-view columns map and is not in nonDataColumns (same for the newly exposed ORIGINAL_AMOUNT below), so selecting these new options in r/:reportID/settings/columns silently drops them and they never render.

Useful? React with 👍 / 👎.

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.

@MelvinBot the bare revert overcorrected — it removed the always-on behavior but added no data-presence path, so Posted and Original amount are now never rendered in the report view (even when transactions do have a posting date / foreign amount).

Please implement the data-driven approach instead of nonDataColumns

Also please add a getColumnsToShow({isExpenseReportView: true}) regression test for those columns

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done — implemented the data-driven approach in 25418e7.

Instead of nonDataColumns, getColumnsToShow now populates the report-view data-presence map for both columns, so they render when the data exists and are dropped when it doesn't:

  • ORIGINAL_AMOUNT — set to true in the report view when a currency conversion exists (hasExchangeRate), mirroring the existing search-page behavior. SearchUIUtils.ts:5850-5857
  • POSTED — set to true when at least one transaction in the report has a posting date (transaction.posted). SearchUIUtils.ts:5859-5864

Both are also seeded as false in the report-view columns map so they default to hidden and are only kept by the existing columns[col] presence check (no nonDataColumns entry). Search-page behavior is unchanged.

Added 4 getColumnsToShow({isExpenseReportView: true}) regression tests covering hide-when-empty / show-when-present for each column: SearchUIUtilsTest.ts:8894-8957.

Checks: SearchUIUtilsTest 351/351 passed (incl. the 4 new tests); typecheck and prettier clean. ⚠️ I couldn't run ESLint locally — this environment's lint-changed relies on git merge-base origin/main HEAD, which fails on the shallow PR checkout, and direct eslint invocation isn't available here. The change adds no new imports and follows the existing data-presence patterns, and tsgo typecheck passed, but a CI lint pass should confirm.

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.

@MelvinBot the data-driven direction is right, but this is now too broad: the POSTED and ORIGINAL_AMOUNT setters aren't gated to an explicit selection, so they also fire in the default report view. I verified that for a report whose transactions have a posting date and a currency conversion — with no custom column selection — both columns now show by default. That means foreign-currency reports render both Amount and Original amount by default, and card reports render Posted by default. That's beyond what we want here; these should only appear when the user explicitly picks them.

Please gate both behind customResult (keep TOTAL_AMOUNT as-is):

if (hasExchangeRate) {
    if (isExpenseReportView) {
        columns[CONST.SEARCH.TABLE_COLUMNS.TOTAL_AMOUNT] = true;
        if (customResult) {
            columns[CONST.SEARCH.TABLE_COLUMNS.ORIGINAL_AMOUNT] = true;
        }
    } else {
        columns[CONST.SEARCH.TABLE_COLUMNS.ORIGINAL_AMOUNT] = true;
    }
}
if (customResult && isExpenseReportView && transaction.posted) {
    columns[CONST.SEARCH.TABLE_COLUMNS.POSTED] = true;
}

Also add a default-view regression test: with a transaction that has both a posting date and a conversion but no explicit column selection, assert POSTED and ORIGINAL_AMOUNT are not returned. The current 4 tests only cover the custom path, so this default-view behavior slipped through untested.

EXPORTED: {column: this.TABLE_COLUMNS.EXPORTED, search: true, reportView: false},
MERCHANT: {column: this.TABLE_COLUMNS.MERCHANT, search: true, reportView: true},
DESCRIPTION: {column: this.TABLE_COLUMNS.DESCRIPTION, search: true, reportView: true},
FROM: {column: this.TABLE_COLUMNS.FROM, search: true, reportView: false},
TO: {column: this.TABLE_COLUMNS.TO, search: true, reportView: false},
POLICY_NAME: {column: this.TABLE_COLUMNS.POLICY_NAME, search: true, reportView: false},
CARD: {column: this.TABLE_COLUMNS.CARD, search: true, reportView: true},
CATEGORY: {column: this.TABLE_COLUMNS.CATEGORY, search: true, reportView: true},
CATEGORY_GL_CODE: {column: this.TABLE_COLUMNS.CATEGORY_GL_CODE, search: true, reportView: true},
ATTENDEES: {column: this.TABLE_COLUMNS.ATTENDEES, search: true, reportView: true},
TOTAL_PER_ATTENDEE: {column: this.TABLE_COLUMNS.TOTAL_PER_ATTENDEE, search: true, reportView: true},
TAG: {column: this.TABLE_COLUMNS.TAG, search: true, reportView: true},
EXCHANGE_RATE: {column: this.TABLE_COLUMNS.EXCHANGE_RATE, search: true, reportView: true},
ORIGINAL_AMOUNT: {column: this.TABLE_COLUMNS.ORIGINAL_AMOUNT, search: true, reportView: true},
REPORT_ID: {column: this.TABLE_COLUMNS.REPORT_ID, search: true, reportView: false},
BASE_62_REPORT_ID: {column: this.TABLE_COLUMNS.BASE_62_REPORT_ID, search: true, reportView: false},
REIMBURSABLE: {column: this.TABLE_COLUMNS.REIMBURSABLE, search: true, reportView: true},
BILLABLE: {column: this.TABLE_COLUMNS.BILLABLE, search: true, reportView: true},
MCC: {column: this.TABLE_COLUMNS.MCC, search: true, reportView: true},
TAX_CODE: {column: this.TABLE_COLUMNS.TAX_CODE, search: true, reportView: true},
TAX_RATE: {column: this.TABLE_COLUMNS.TAX_RATE, search: true, reportView: true},
TAX_AMOUNT: {column: this.TABLE_COLUMNS.TAX_AMOUNT, search: true, reportView: true},
TITLE: {column: this.TABLE_COLUMNS.TITLE, search: true, reportView: false},
AMOUNT: {column: this.TABLE_COLUMNS.TOTAL_AMOUNT, search: true, reportView: true},
TOTAL: {column: this.TABLE_COLUMNS.TOTAL, search: false, reportView: true},
EXPORTED_TO: {column: this.TABLE_COLUMNS.EXPORTED_TO, search: true, reportView: false},
ACTION: {column: this.TABLE_COLUMNS.ACTION, search: true, reportView: false},
WITHDRAWAL_ID: {column: this.TABLE_COLUMNS.WITHDRAWAL_ID, search: true, reportView: true},
};
},
get TYPE_CUSTOM_COLUMNS() {
return {
EXPENSE: {
RECEIPT: this.TABLE_COLUMNS.RECEIPT,
DATE: this.TABLE_COLUMNS.DATE,
STATUS: this.TABLE_COLUMNS.STATUS,
SUBMITTED: this.TABLE_COLUMNS.SUBMITTED,
APPROVED: this.TABLE_COLUMNS.APPROVED,
POSTED: this.TABLE_COLUMNS.POSTED,
EXPORTED: this.TABLE_COLUMNS.EXPORTED,
MERCHANT: this.TABLE_COLUMNS.MERCHANT,
DESCRIPTION: this.TABLE_COLUMNS.DESCRIPTION,
FROM: this.TABLE_COLUMNS.FROM,
TO: this.TABLE_COLUMNS.TO,
POLICY_NAME: this.TABLE_COLUMNS.POLICY_NAME,
CARD: this.TABLE_COLUMNS.CARD,
CATEGORY: this.TABLE_COLUMNS.CATEGORY,
CATEGORY_GL_CODE: this.TABLE_COLUMNS.CATEGORY_GL_CODE,
ATTENDEES: this.TABLE_COLUMNS.ATTENDEES,
TOTAL_PER_ATTENDEE: this.TABLE_COLUMNS.TOTAL_PER_ATTENDEE,
TAG: this.TABLE_COLUMNS.TAG,
EXCHANGE_RATE: this.TABLE_COLUMNS.EXCHANGE_RATE,
ORIGINAL_AMOUNT: this.TABLE_COLUMNS.ORIGINAL_AMOUNT,
REPORT_ID: this.TABLE_COLUMNS.REPORT_ID,
BASE_62_REPORT_ID: this.TABLE_COLUMNS.BASE_62_REPORT_ID,
REIMBURSABLE: this.TABLE_COLUMNS.REIMBURSABLE,
BILLABLE: this.TABLE_COLUMNS.BILLABLE,
MCC: this.TABLE_COLUMNS.MCC,
TAX_CODE: this.TABLE_COLUMNS.TAX_CODE,
TAX_RATE: this.TABLE_COLUMNS.TAX_RATE,
TAX_AMOUNT: this.TABLE_COLUMNS.TAX_AMOUNT,
TITLE: this.TABLE_COLUMNS.TITLE,
AMOUNT: this.TABLE_COLUMNS.TOTAL_AMOUNT,
EXPORTED_TO: this.TABLE_COLUMNS.EXPORTED_TO,
ACTION: this.TABLE_COLUMNS.ACTION,
WITHDRAWAL_ID: this.TABLE_COLUMNS.WITHDRAWAL_ID,
},
// Derived from COLUMN_AVAILABILITY: every column flagged `search`, in declaration order.
EXPENSE: Object.fromEntries(
Object.entries(this.COLUMN_AVAILABILITY)
.filter(([, availability]) => availability.search)
.map(([key, availability]) => [key, availability.column] as const),
),
EXPENSE_REPORT: {
AVATAR: this.TABLE_COLUMNS.AVATAR,
DATE: this.TABLE_COLUMNS.DATE,
Expand All @@ -6703,27 +6725,13 @@ const CONST = {
CHAT: {},
};
},
// Derived from COLUMN_AVAILABILITY: every column flagged `reportView`, in declaration order.
get REPORT_DETAILS_CUSTOM_COLUMNS() {
return {
RECEIPT: this.TABLE_COLUMNS.RECEIPT,
DATE: this.TABLE_COLUMNS.DATE,
MERCHANT: this.TABLE_COLUMNS.MERCHANT,
DESCRIPTION: this.TABLE_COLUMNS.DESCRIPTION,
CARD: this.TABLE_COLUMNS.CARD,
CATEGORY: this.TABLE_COLUMNS.CATEGORY,
CATEGORY_GL_CODE: this.TABLE_COLUMNS.CATEGORY_GL_CODE,
TAG: this.TABLE_COLUMNS.TAG,
EXCHANGE_RATE: this.TABLE_COLUMNS.EXCHANGE_RATE,
REIMBURSABLE: this.TABLE_COLUMNS.REIMBURSABLE,
BILLABLE: this.TABLE_COLUMNS.BILLABLE,
MCC: this.TABLE_COLUMNS.MCC,
TAX_CODE: this.TABLE_COLUMNS.TAX_CODE,
TAX_RATE: this.TABLE_COLUMNS.TAX_RATE,
TAX_AMOUNT: this.TABLE_COLUMNS.TAX_AMOUNT,
AMOUNT: this.TABLE_COLUMNS.TOTAL_AMOUNT,
TOTAL: this.TABLE_COLUMNS.TOTAL,
WITHDRAWAL_ID: this.TABLE_COLUMNS.WITHDRAWAL_ID,
};
return Object.fromEntries(
Object.entries(this.COLUMN_AVAILABILITY)
.filter(([, availability]) => availability.reportView)
.map(([key, availability]) => [key, availability.column] as const),
);
},
get GROUP_CUSTOM_COLUMNS() {
return {
Expand Down
20 changes: 17 additions & 3 deletions src/libs/SearchUIUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5656,6 +5656,7 @@ function getColumnsToShow({
[CONST.SEARCH.TABLE_COLUMNS.RECEIPT]: true,
[CONST.SEARCH.TABLE_COLUMNS.TYPE]: true,
[CONST.SEARCH.TABLE_COLUMNS.DATE]: true,
[CONST.SEARCH.TABLE_COLUMNS.POSTED]: false,
[CONST.SEARCH.TABLE_COLUMNS.MERCHANT]: false,
[CONST.SEARCH.TABLE_COLUMNS.DESCRIPTION]: false,
[CONST.SEARCH.TABLE_COLUMNS.CATEGORY]: false,
Expand All @@ -5667,6 +5668,7 @@ function getColumnsToShow({
[CONST.SEARCH.TABLE_COLUMNS.TAX_RATE]: false,
[CONST.SEARCH.TABLE_COLUMNS.TAX_AMOUNT]: false,
[CONST.SEARCH.TABLE_COLUMNS.EXCHANGE_RATE]: false,
[CONST.SEARCH.TABLE_COLUMNS.ORIGINAL_AMOUNT]: false,
[CONST.SEARCH.TABLE_COLUMNS.REIMBURSABLE]: shouldShowReimbursableColumn,
[CONST.SEARCH.TABLE_COLUMNS.BILLABLE]: shouldShowBillableColumn,
[CONST.SEARCH.TABLE_COLUMNS.TOTAL_AMOUNT]: false,
Expand Down Expand Up @@ -5839,17 +5841,29 @@ function getColumnsToShow({
if (hasExchangeRate) {
columns[CONST.SEARCH.TABLE_COLUMNS.EXCHANGE_RATE] = true;
}
// Expense report view: TOTAL (workspace currency) is always shown; add AMOUNT
// (transaction's own currency) when a conversion exists so both are visible.
// Search page: show ORIGINAL_AMOUNT column (transaction's original amount).
// Expense report view: TOTAL (workspace currency) is always shown when a conversion
// exists. ORIGINAL_AMOUNT (the transaction's original/foreign amount) is a separate,
// user-selectable report column — in the report view it's gated behind an explicit
// selection (customResult) so it never renders by default, only when the user picks it.
// Search page: ORIGINAL_AMOUNT stays data-driven (shown whenever a conversion exists).
if (hasExchangeRate) {
if (isExpenseReportView) {
columns[CONST.SEARCH.TABLE_COLUMNS.TOTAL_AMOUNT] = true;
if (customResult) {
columns[CONST.SEARCH.TABLE_COLUMNS.ORIGINAL_AMOUNT] = true;
}
} else {
columns[CONST.SEARCH.TABLE_COLUMNS.ORIGINAL_AMOUNT] = true;
}
}

// POSTED (card posting date) is a user-selectable report column. In the report view it's
// gated behind an explicit selection (customResult) so it never renders by default —
// it shows only when the user picks it and the transaction actually has a posting date.
if (customResult && isExpenseReportView && transaction.posted) {
columns[CONST.SEARCH.TABLE_COLUMNS.POSTED] = true;
}

if (!Array.isArray(data)) {
if (transactionReport?.submitted) {
columns[CONST.SEARCH.TABLE_COLUMNS.SUBMITTED] = true;
Expand Down
130 changes: 130 additions & 0 deletions tests/unit/Search/ColumnAvailabilityTest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import CONST from '@src/CONST';

/**
* Guard tests for the single source of truth that drives the two expense column pickers.
*
* `CONST.SEARCH.COLUMN_AVAILABILITY` declares, per transaction-level column, whether it is available in the
* Search picker (`search`) and/or the single-report picker (`reportView`). Both
* `CONST.SEARCH.TYPE_CUSTOM_COLUMNS.EXPENSE` and `CONST.SEARCH.REPORT_DETAILS_CUSTOM_COLUMNS` are derived from it.
*
* These tests fail if a new `TABLE_COLUMNS` value is added without a deliberate availability decision (either an
* entry in `COLUMN_AVAILABILITY` or an explicit listing under another surface), preventing the two pickers from
* silently drifting apart the way they did historically.
*/
describe('Column availability single source of truth', () => {
const TABLE_COLUMNS = CONST.SEARCH.TABLE_COLUMNS;
const allTableColumns = new Set<string>(Object.values(TABLE_COLUMNS));
const availabilityColumns: string[] = Object.values(CONST.SEARCH.COLUMN_AVAILABILITY).map((availability) => availability.column);

// Columns that intentionally belong to surfaces other than the two expense column pickers. Every
// TABLE_COLUMNS value must be either classified in COLUMN_AVAILABILITY or listed here, so adding a new
// column forces a deliberate decision instead of silently doing nothing.
const OTHER_SURFACE_COLUMNS = new Set<string>([
// Structural / row-chrome columns rendered implicitly, never user-toggleable.
TABLE_COLUMNS.AVATAR,
TABLE_COLUMNS.TYPE,
TABLE_COLUMNS.COMMENTS,
// Task search view.
TABLE_COLUMNS.ASSIGNEE,
TABLE_COLUMNS.IN,
// Expense-report (report list) view.
TABLE_COLUMNS.REIMBURSABLE_TOTAL,
TABLE_COLUMNS.NON_REIMBURSABLE_TOTAL,
// Grouped search views.
TABLE_COLUMNS.EXPENSES,
TABLE_COLUMNS.FEED,
TABLE_COLUMNS.WITHDRAWN,
TABLE_COLUMNS.BANK_ACCOUNT,
TABLE_COLUMNS.GROUP_FROM,
TABLE_COLUMNS.GROUP_EXPENSES,
TABLE_COLUMNS.GROUP_TOTAL,
TABLE_COLUMNS.GROUP_CARD,
TABLE_COLUMNS.GROUP_FEED,
TABLE_COLUMNS.GROUP_BANK_ACCOUNT,
TABLE_COLUMNS.GROUP_WITHDRAWN,
TABLE_COLUMNS.GROUP_WITHDRAWAL_ID,
TABLE_COLUMNS.GROUP_CATEGORY,
TABLE_COLUMNS.GROUP_MERCHANT,
TABLE_COLUMNS.GROUP_TAG,
TABLE_COLUMNS.GROUP_MONTH,
TABLE_COLUMNS.GROUP_WEEK,
TABLE_COLUMNS.GROUP_YEAR,
TABLE_COLUMNS.GROUP_QUARTER,
TABLE_COLUMNS.GROUP_WITHDRAWAL_STATUS,
]);

test('every TABLE_COLUMNS value is classified in COLUMN_AVAILABILITY or owned by another surface', () => {
const unclassified = [...allTableColumns].filter((column) => !availabilityColumns.includes(column) && !OTHER_SURFACE_COLUMNS.has(column));

// If this fails, a new TABLE_COLUMNS value was added without deciding its picker availability.
// Add it to CONST.SEARCH.COLUMN_AVAILABILITY (with search/reportView flags) or, if it belongs to
// another surface (grouped/report-list/task view), to OTHER_SURFACE_COLUMNS above.
expect(unclassified).toEqual([]);
});

test('COLUMN_AVAILABILITY and OTHER_SURFACE_COLUMNS are disjoint', () => {
const overlap = availabilityColumns.filter((column) => OTHER_SURFACE_COLUMNS.has(column));
expect(overlap).toEqual([]);
});

test('every value in COLUMN_AVAILABILITY is a valid TABLE_COLUMNS value', () => {
const invalid = availabilityColumns.filter((column) => !allTableColumns.has(column));
expect(invalid).toEqual([]);
});

test('TYPE_CUSTOM_COLUMNS.EXPENSE is exactly the search-enabled columns in declaration order', () => {
const expectedSearchColumns = Object.values(CONST.SEARCH.COLUMN_AVAILABILITY)
.filter((availability) => availability.search)
.map((availability) => availability.column);
expect(Object.values(CONST.SEARCH.TYPE_CUSTOM_COLUMNS.EXPENSE)).toEqual(expectedSearchColumns);
});

test('REPORT_DETAILS_CUSTOM_COLUMNS is exactly the reportView-enabled columns in declaration order', () => {
const expectedReportColumns = Object.values(CONST.SEARCH.COLUMN_AVAILABILITY)
.filter((availability) => availability.reportView)
.map((availability) => availability.column);
expect(Object.values(CONST.SEARCH.REPORT_DETAILS_CUSTOM_COLUMNS)).toEqual(expectedReportColumns);
});

test('every derived picker column is a valid TABLE_COLUMNS value', () => {
const expenseColumns = Object.values(CONST.SEARCH.TYPE_CUSTOM_COLUMNS.EXPENSE);
const reportColumns = Object.values(CONST.SEARCH.REPORT_DETAILS_CUSTOM_COLUMNS);
expect(expenseColumns.filter((column) => !allTableColumns.has(column))).toEqual([]);
expect(reportColumns.filter((column) => !allTableColumns.has(column))).toEqual([]);
});

test('the four transaction-level columns are aligned into the single-report picker', () => {
const reportColumns = Object.values(CONST.SEARCH.REPORT_DETAILS_CUSTOM_COLUMNS);
expect(reportColumns).toContain(TABLE_COLUMNS.POSTED);
expect(reportColumns).toContain(TABLE_COLUMNS.ATTENDEES);
expect(reportColumns).toContain(TABLE_COLUMNS.TOTAL_PER_ATTENDEE);
expect(reportColumns).toContain(TABLE_COLUMNS.ORIGINAL_AMOUNT);
});

test('report-level columns stay out of the single-report picker', () => {
const reportColumns = Object.values(CONST.SEARCH.REPORT_DETAILS_CUSTOM_COLUMNS);
const reportLevelColumns = [
TABLE_COLUMNS.STATUS,
TABLE_COLUMNS.SUBMITTED,
TABLE_COLUMNS.APPROVED,
TABLE_COLUMNS.EXPORTED,
TABLE_COLUMNS.EXPORTED_TO,
TABLE_COLUMNS.FROM,
TABLE_COLUMNS.TO,
TABLE_COLUMNS.POLICY_NAME,
TABLE_COLUMNS.REPORT_ID,
TABLE_COLUMNS.BASE_62_REPORT_ID,
TABLE_COLUMNS.TITLE,
TABLE_COLUMNS.ACTION,
];
for (const column of reportLevelColumns) {
expect(reportColumns).not.toContain(column);
}
});

test('the derived picker lists match their snapshots', () => {
// Snapshots make any future change to either picker list a deliberate, reviewed update.
expect(Object.values(CONST.SEARCH.TYPE_CUSTOM_COLUMNS.EXPENSE)).toMatchSnapshot('TYPE_CUSTOM_COLUMNS.EXPENSE');
expect(Object.values(CONST.SEARCH.REPORT_DETAILS_CUSTOM_COLUMNS)).toMatchSnapshot('REPORT_DETAILS_CUSTOM_COLUMNS');
});
});
Loading
Loading