Files
dbx/packages/app-tests/repro-issue-11956.test.ts

78 lines
3.1 KiB
TypeScript
Vendored

// Regression tests for upstream issue t8y2/dbx#11956:
// 「对查询表数据进行搜索时,数据存在但搜索不到」
// The result-grid Ctrl+F search runs over the FORMATTED DISPLAY text of each
// cell, which DataGrid.vue truncates with limitDataGridCellDisplay at
// DATA_GRID_CELL_DISPLAY_MAX_LENGTH (256) characters. A search term past that
// cut was invisible to Ctrl+F while a server-side WHERE found it.
//
// Fix: the match scan re-checks the full raw value of cells whose display text
// is truncated (ends with "..."), so matches past the display cut are found.
//
// The wiring below mirrors DataGrid.vue's useDataGridSearch call for a plain
// text column (DataGrid.vue:1146-1170): search text = lowercase of the
// 256-char-truncated display value.
import { nextTick } from "vue";
import { test, vi } from "vitest";
import { strict as assert } from "node:assert";
import { useDataGridSearch } from "../../apps/desktop/src/composables/useDataGridSearch.ts";
import { limitDataGridCellDisplay } from "../../apps/desktop/src/lib/dataGrid/cellValue.ts";
async function flushSearchDebounce() {
await nextTick();
vi.runOnlyPendingTimers();
await nextTick();
await nextTick();
}
// Same shape as DataGrid.vue's getCellSearchText for a plain text column.
const cellSearchText = (row: string[], column: number): string => limitDataGridCellDisplay(String(row[column] ?? "")).toLowerCase();
function longValue(prefix: string, needle: string, totalLength: number): string {
const head = `${prefix}${"x".repeat(totalLength)}`.slice(0, totalLength);
// Place the needle just past the 256-character display cut.
return head.slice(0, 260) + needle + head.slice(260 + needle.length);
}
test("finds values whose match sits past the 256-char display cut", async () => {
vi.useFakeTimers();
const rows = [
[longValue("row A: ", "needle_a", 400)],
[longValue("row B: ", "needle_b", 400)],
[longValue("row C: ", "needle_c", 400)],
// Control: same row shape but the keyword within the first 256 chars.
[longValue("row D: ", "needle_d", 100)],
];
const search = useDataGridSearch({
columns: ["content"],
rows,
getCellSearchText: cellSearchText,
getCellRawSearchText: (row, col) => String(row[col] ?? ""),
includeColumnMatches: false,
});
for (const needle of ["needle_a", "needle_b", "needle_c", "needle_d"]) {
search.searchText.value = needle;
await flushSearchDebounce();
assert.equal(search.matchCount.value, 1, `Ctrl+F "${needle}" should match its row; the data exists and WHERE finds it`);
}
});
test("does not report truncated cells whose raw value has no match", async () => {
vi.useFakeTimers();
// A raw value that legitimately ends with "..." but never contains the query
// must not become a false positive through the raw re-check.
const rows = [["x".repeat(300) + "..."]];
const search = useDataGridSearch({
columns: ["content"],
rows,
getCellSearchText: cellSearchText,
getCellRawSearchText: (row, col) => String(row[col] ?? ""),
includeColumnMatches: false,
});
search.searchText.value = "needle_none";
await flushSearchDebounce();
assert.equal(search.matchCount.value, 0);
});