const should = require("should"); const sinon = require("sinon"); const NR_TEST_UTILS = require("nr-test-utils"); // Path to the search.js module const searchModulePath = NR_TEST_UTILS.resolve("@node-red/editor-client/src/js/ui/search.js"); describe("editor-client/ui/search", function() { let search; let mockRED; beforeEach(function() { // Set up minimal RED global mock - only what's needed for tests mockRED = { utils: { getNodeLabel: sinon.stub() } }; global.RED = mockRED; // Clear require cache to get fresh module instance delete require.cache[searchModulePath]; search = require(searchModulePath); // Reset the index for each test search._index = {}; }); afterEach(function() { sinon.restore(); delete global.RED; delete require.cache[searchModulePath]; }); describe("indexNode", function() { it("preserves original label casing in search results", function() { const node = { id: "node1", type: "tab", _def: { category: "config" } }; mockRED.utils.getNodeLabel.returns("MyFlow Name"); search._indexNode(node); // Verify the index key is lowercase (for case-insensitive searching) should.exist(search._index["myflow name"]); // Verify the stored label preserves original casing search._index["myflow name"]["node1"].label.should.equal("MyFlow Name"); }); it("indexes node with mixed case label correctly", function() { const node = { id: "node2", type: "subflow", _def: { category: "subflows" } }; mockRED.utils.getNodeLabel.returns("MySubFlow_Test"); search._indexNode(node); // Index key should be lowercase should.exist(search._index["mysubflow_test"]); // Label should preserve original casing search._index["mysubflow_test"]["node2"].label.should.equal("MySubFlow_Test"); }); it("handles uppercase labels", function() { const node = { id: "node3", type: "tab", _def: { category: "config" } }; mockRED.utils.getNodeLabel.returns("UPPERCASE FLOW"); search._indexNode(node); should.exist(search._index["uppercase flow"]); search._index["uppercase flow"]["node3"].label.should.equal("UPPERCASE FLOW"); }); it("handles lowercase labels", function() { const node = { id: "node4", type: "tab", _def: { category: "config" } }; mockRED.utils.getNodeLabel.returns("lowercase flow"); search._indexNode(node); should.exist(search._index["lowercase flow"]); search._index["lowercase flow"]["node4"].label.should.equal("lowercase flow"); }); it("stores node reference correctly", function() { const node = { id: "node5", type: "tab", _def: { category: "config" } }; mockRED.utils.getNodeLabel.returns("Test Flow"); search._indexNode(node); search._index["test flow"]["node5"].node.should.equal(node); }); it("handles nodes without labels by falling back to id", function() { const node = { id: "node6", type: "tab", _def: { category: "config" } }; mockRED.utils.getNodeLabel.returns(null); search._indexNode(node); // When there's no label from getNodeLabel, // the node is still indexed by its id should.exist(search._index["node6"]); search._index["node6"]["node6"].label.should.equal("node6"); }); }); describe("search", function() { it("finds nodes with case-insensitive search", function() { // Manually set up index with mixed case labels search._index = { "myflow": { "node1": { node: { id: "node1", type: "tab", _def: { category: "config" } }, label: "MyFlow" } } }; // Search with lowercase should find the node const results = search.search("myflow"); results.length.should.equal(1); results[0].label.should.equal("MyFlow"); }); it("returns preserved casing in search results", function() { search._index = { "test subflow": { "node1": { node: { id: "node1", type: "subflow", _def: { category: "subflows" } }, label: "Test SubFlow" } } }; const results = search.search("test"); results.length.should.equal(1); results[0].label.should.equal("Test SubFlow"); }); }); });