diff --git a/src/components/__tests__/CustomListEntriesEditor-test.tsx b/src/components/__tests__/CustomListEntriesEditor-test.tsx deleted file mode 100644 index 880ca46b43..0000000000 --- a/src/components/__tests__/CustomListEntriesEditor-test.tsx +++ /dev/null @@ -1,1461 +0,0 @@ -import { expect } from "chai"; -import { stub } from "sinon"; -import * as React from "react"; -import { shallow, mount } from "enzyme"; -import { Button } from "library-simplified-reusable-components"; -import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd"; - -import CustomListEntriesEditor from "../CustomListEntriesEditor"; - -import { AudioHeadphoneIcon, BookIcon } from "@nypl/dgx-svg-icons"; -import * as PropTypes from "prop-types"; - -describe("CustomListEntriesEditor", () => { - let addAllEntries; - let addEntry; - let deleteAllEntries; - let deleteEntry; - let loadMoreSearchResults; - let loadMoreEntries; - let refreshResults; - let childContextTypes; - let fullContext; - - const searchResultsData = { - id: "id", - url: "url", - title: "title", - lanes: [], - navigationLinks: [], - books: [ - { - id: "1", - title: "result 1", - authors: ["author 1"], - url: "/some/url1", - language: "eng", - raw: { - $: { "schema:additionalType": { value: "http://schema.org/EBook" } }, - }, - }, - { - id: "2", - title: "result 2", - authors: ["author 2a", "author 2b"], - url: "/some/url2", - language: "eng", - raw: { - $: { - "schema:additionalType": { - value: "http://bib.schema.org/Audiobook", - }, - }, - }, - }, - { - id: "3", - title: "result 3", - authors: ["author 3"], - url: "/some/url3", - language: "eng", - raw: { - $: { "schema:additionalType": { value: "http://schema.org/EBook" } }, - }, - }, - ], - }; - - const entriesData = [ - { - id: "A", - title: "entry A", - authors: ["author A"], - url: "/some/urlA", - raw: { - $: { "schema:additionalType": { value: "http://schema.org/EBook" } }, - }, - }, - { - id: "B", - title: "entry B", - authors: ["author B1", "author B2"], - url: "/some/urlB", - raw: { - $: { - "schema:additionalType": { value: "http://bib.schema.org/Audiobook" }, - }, - }, - }, - ]; - - beforeEach(() => { - addAllEntries = stub(); - addEntry = stub(); - deleteAllEntries = stub(); - deleteEntry = stub(); - loadMoreSearchResults = stub(); - loadMoreEntries = stub(); - refreshResults = stub(); - - childContextTypes = { - pathFor: PropTypes.func.isRequired, - router: PropTypes.object.isRequired, - }; - - fullContext = Object.assign( - {}, - { - pathFor: stub().returns("url"), - router: { - createHref: stub(), - push: stub(), - isActive: stub(), - replace: stub(), - go: stub(), - goBack: stub(), - goForward: stub(), - setRouteLeaveHook: stub(), - }, - } - ); - }); - - it("renders search results", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const resultsContainer = wrapper.find(".custom-list-search-results"); - - expect(resultsContainer.length).to.equal(1); - - const droppable = resultsContainer.find(Droppable); - - expect(droppable.length).to.equal(1); - - const results = droppable.find(Draggable); - - expect(results.length).to.equal(3); - expect(results.at(0).text()).to.contain("result 1"); - expect(results.at(0).text()).to.contain("author 1"); - expect(results.at(1).text()).to.contain("result 2"); - expect(results.at(1).text()).to.contain("author 2a, author 2b"); - expect(results.at(2).text()).to.contain("result 3"); - expect(results.at(2).text()).to.contain("author 3"); - }); - - it("does not render search results when isOwner is false", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const resultsContainer = wrapper.find(".custom-list-search-results"); - - expect(resultsContainer.length).to.equal(0); - }); - - it("calls refreshResults when the refresh button is clicked", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const refreshButton = wrapper.find(".btn.refresh-button"); - - refreshButton.at(0).simulate("click"); - - expect(refreshResults.callCount).to.equal(1); - }); - - it("disables the refresh button when isFetchingSearchResults is true", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const refreshButton = wrapper.find(".btn.refresh-button"); - - expect(refreshButton.prop("disabled")).to.equal(true); - }); - - it("disables the refresh button when isFetchingSearchResults is true", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const refreshButton = wrapper.find(".btn.refresh-button"); - - expect(refreshButton.prop("disabled")).to.equal(true); - }); - - it("shows a loading message when isFetchingSearchResults is true", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const loadingIndicator = wrapper.find(".list-loading"); - - expect(loadingIndicator.length).to.equal(1); - expect(loadingIndicator.text()).to.contain("Loading"); - }); - - it("renders a link to view each search result", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const resultsContainer = wrapper.find(".custom-list-search-results"); - - expect(resultsContainer.length).to.equal(1); - - const droppable = resultsContainer.find(Droppable); - - expect(droppable.length).to.equal(1); - - const results = droppable.find(Draggable); - - expect(results.length).to.equal(3); - - expect(results.at(0).find("CatalogLink").text()).to.equal("View details"); - expect(results.at(0).find("CatalogLink").prop("bookUrl")).to.equal( - "/some/url1" - ); - - expect(results.at(1).find("CatalogLink").text()).to.equal("View details"); - expect(results.at(1).find("CatalogLink").prop("bookUrl")).to.equal( - "/some/url2" - ); - - expect(results.at(2).find("CatalogLink").text()).to.equal("View details"); - expect(results.at(2).find("CatalogLink").prop("bookUrl")).to.equal( - "/some/url3" - ); - }); - - it("does not include the opds feed url in links to view search results", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const results = wrapper.find(".custom-list-search-results Draggable"); - - expect(results.at(0).find("CatalogLink").prop("collectionUrl")).to.equal( - undefined - ); - - expect(results.at(1).find("CatalogLink").prop("collectionUrl")).to.equal( - undefined - ); - - expect(results.at(2).find("CatalogLink").prop("collectionUrl")).to.equal( - undefined - ); - }); - - it("renders an SVG icon for each search result", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const resultsContainer = wrapper.find(".custom-list-search-results"); - const audioSVGs = resultsContainer.find(AudioHeadphoneIcon); - const bookSVGs = resultsContainer.find(BookIcon); - - expect(audioSVGs.length).to.equal(1); - expect(bookSVGs.length).to.equal(2); - }); - - it("doesn't render an SVG icon for books with a bad medium value", () => { - searchResultsData.books[2].raw["$"]["schema:additionalType"].value = ""; - - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const resultsContainer = wrapper.find(".custom-list-search-results"); - const audioSVGs = resultsContainer.find(AudioHeadphoneIcon); - const bookSVGs = resultsContainer.find(BookIcon); - - expect(audioSVGs.length).to.equal(1); - expect(bookSVGs.length).to.equal(1); - - searchResultsData.books[2].raw["$"]["schema:additionalType"].value = - "http://schema.org/EBook"; - }); - - it("renders list entries", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const entriesContainer = wrapper.find(".custom-list-entries"); - - expect(entriesContainer.length).to.equal(1); - - const droppable = entriesContainer.find(Droppable); - - expect(droppable.length).to.equal(1); - - const entries = droppable.find(Draggable); - - expect(entries.length).to.equal(2); - - expect(entries.at(0).text()).to.contain("entry A"); - expect(entries.at(0).text()).to.contain("author A"); - expect(entries.at(1).text()).to.contain("entry B"); - expect(entries.at(1).text()).to.contain("author B1, author B2"); - - const display = wrapper.find(".custom-list-entries h4"); - - expect(display.text()).to.equal( - "List Entries: Displaying 1 - 2 of 2 books" - ); - }); - - it("makes list entries read only if autoUpdate is true", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const entriesContainer = wrapper.find(".custom-list-entries"); - const removeAllButton = entriesContainer.find(".droppable-header button"); - - expect(removeAllButton.length).to.equal(0); - - const removeEntryButtons = entriesContainer.find( - ".custom-list-entry button" - ); - - expect(removeEntryButtons.length).to.equal(0); - }); - - it("renders an auto update status if autoUpdate is true", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - let status; - - status = wrapper.find(".custom-list-entries .auto-update-status-name"); - expect(status.text()).to.equal("Status: New"); - - wrapper.setProps({ isSearchModified: true }); - - status = wrapper.find(".custom-list-entries .auto-update-status-name"); - expect(status.text()).to.equal("Status: New"); - - wrapper.setProps({ - listId: "123", - isSearchModified: false, - autoUpdateStatus: "init", - }); - - status = wrapper.find(".custom-list-entries .auto-update-status-name"); - expect(status.text()).to.equal("Status: Initializing"); - - wrapper.setProps({ isSearchModified: true }); - - status = wrapper.find(".custom-list-entries .auto-update-status-name"); - expect(status.text()).to.equal("Status: Search criteria modified"); - - wrapper.setProps({ isSearchModified: false, autoUpdateStatus: "updated" }); - - status = wrapper.find(".custom-list-entries .auto-update-status-name"); - expect(status.text()).to.equal("Status: Updated"); - - wrapper.setProps({ isSearchModified: true }); - - status = wrapper.find(".custom-list-entries .auto-update-status-name"); - expect(status.text()).to.equal("Status: Search criteria modified"); - - wrapper.setProps({ - isSearchModified: false, - autoUpdateStatus: "repopulate", - }); - - status = wrapper.find(".custom-list-entries .auto-update-status-name"); - expect(status.text()).to.equal("Status: Repopulating"); - - wrapper.setProps({ isSearchModified: true }); - - status = wrapper.find(".custom-list-entries .auto-update-status-name"); - expect(status.text()).to.equal("Status: Search criteria modified"); - - wrapper.setProps({ autoUpdate: false }); - - status = wrapper.find(".custom-list-entries .auto-update-status-name"); - - expect(status.length).to.equal(0); - }); - - it("renders a link to view each entry", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const entriesContainer = wrapper.find(".custom-list-entries"); - - expect(entriesContainer.length).to.equal(1); - - const droppable = entriesContainer.find(Droppable); - - expect(droppable.length).to.equal(1); - - const entries = droppable.find(Draggable); - - expect(entries.length).to.equal(2); - - expect(entries.at(0).find("CatalogLink").text()).to.equal("View details"); - expect(entries.at(0).find("CatalogLink").prop("bookUrl")).to.equal( - "/some/urlA" - ); - - expect(entries.at(1).find("CatalogLink").text()).to.equal("View details"); - expect(entries.at(1).find("CatalogLink").prop("bookUrl")).to.equal( - "/some/urlB" - ); - }); - - it("includes the opds feed url in links to view entries", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const entries = wrapper.find(".custom-list-entries Draggable"); - - expect(entries.at(0).find("CatalogLink").prop("collectionUrl")).to.equal( - "opdsFeedUrl" - ); - - expect(entries.at(1).find("CatalogLink").prop("collectionUrl")).to.equal( - "opdsFeedUrl" - ); - }); - - it("renders an SVG icon for each entry", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const entriesContainer = wrapper.find(".custom-list-entries"); - const audioSVGs = entriesContainer.find(AudioHeadphoneIcon); - const bookSVGs = entriesContainer.find(BookIcon); - - expect(audioSVGs.length).to.equal(1); - expect(bookSVGs.length).to.equal(1); - }); - - it("doesn't include search results that are already in the entries list when autoUpdate is false", () => { - const entriesData = [ - { - id: "1", - title: "result 1", - authors: ["author 1"], - language: "eng", - raw: { - $: { - "schema:additionalType": { - value: "http://bib.schema.org/Audiobook", - }, - }, - }, - }, - ]; - - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const resultsContainer = wrapper.find(".custom-list-search-results"); - - expect(resultsContainer.length).to.equal(1); - - const droppable = resultsContainer.find(Droppable); - - expect(droppable.length).to.equal(1); - - const results = droppable.find(Draggable); - - expect(results.length).to.equal(2); - - expect(results.at(0).text()).to.contain("result 2"); - expect(results.at(0).text()).to.contain("author 2a, author 2b"); - expect(results.at(1).text()).to.contain("result 3"); - expect(results.at(1).text()).to.contain("author 3"); - }); - - it("shows all search results, even ones that are in the entries list, when autoUpdate is true", () => { - const entriesData = [ - { - id: "1", - title: "result 1", - authors: ["author 1"], - language: "eng", - raw: { - $: { - "schema:additionalType": { - value: "http://bib.schema.org/Audiobook", - }, - }, - }, - }, - ]; - - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const resultsContainer = wrapper.find(".custom-list-search-results"); - - expect(resultsContainer.length).to.equal(1); - - const droppable = resultsContainer.find(Droppable); - - expect(droppable.length).to.equal(1); - - const results = droppable.find(Draggable); - - expect(results.length).to.equal(3); - expect(results.at(0).text()).to.contain("result 1"); - expect(results.at(0).text()).to.contain("author 1"); - expect(results.at(1).text()).to.contain("result 2"); - expect(results.at(1).text()).to.contain("author 2a, author 2b"); - expect(results.at(2).text()).to.contain("result 3"); - expect(results.at(2).text()).to.contain("author 3"); - }); - - // FIXME: react-beautiful-dnd does not work well in jsdom, so the following drag-and-drop tests - // reach into the render tree to find the DragDropContext, and directly call the onDragStart and - // onDragEnd props. A better way would be to simulate the mouse/keyboard events that occur during - // a drag-and-drop operation, without knowing anything about the implementation. This would be - // possible if the tests ran in real browsers, e.g. by using Karma. - - it("prevents dragging within search results", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - // Simulate starting a drag from search results. - - const dragDropContext = wrapper.find(DragDropContext); - const onDragStart = dragDropContext.prop("onDragStart"); - - onDragStart({ - draggableId: "1", - source: { - droppableId: "search-results", - }, - }); - - wrapper.update(); - - const resultsContainer = wrapper.find(".custom-list-search-results"); - const resultsDroppable = resultsContainer.find(Droppable); - - expect(resultsDroppable.prop("isDropDisabled")).to.equal(true); - }); - - it("prevents dragging within list entries", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - // Simulate starting a drag from list entries. - - const dragDropContext = wrapper.find(DragDropContext); - const onDragStart = dragDropContext.prop("onDragStart"); - - onDragStart({ - draggableId: "A", - source: { - droppableId: "custom-list-entries", - }, - }); - - wrapper.update(); - - const entriesContainer = wrapper.find(".custom-list-entries"); - const entriesDroppable = entriesContainer.find(Droppable); - - expect(entriesDroppable.prop("isDropDisabled")).to.equal(true); - }); - - it("calls addEntry when a book is dragged from search results to list entries", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - // Simulate starting a drag from search results. - - const dragDropContext = wrapper.find(DragDropContext); - const onDragStart = dragDropContext.prop("onDragStart"); - - onDragStart({ - draggableId: "1", - source: { - droppableId: "search-results", - }, - }); - - wrapper.update(); - - const entriesContainer = wrapper.find(".custom-list-entries"); - const entriesDroppable = entriesContainer.find(Droppable); - - expect(entriesDroppable.prop("isDropDisabled")).to.equal(false); - - // Simulate dropping on the entries. - - const onDragEnd = dragDropContext.prop("onDragEnd"); - - onDragEnd({ - draggableId: "1", - source: { - droppableId: "search-results", - }, - destination: { - droppableId: "custom-list-entries", - }, - }); - - wrapper.update(); - - expect(addEntry.callCount).to.equal(1); - expect(addEntry.args[0]).to.deep.equal(["1"]); - }); - - it("shows a message in place of search results when dragging from list entries", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - // Simulate starting a drag from list entries. - - const dragDropContext = wrapper.find(DragDropContext); - const onDragStart = dragDropContext.prop("onDragStart"); - - onDragStart({ - draggableId: "A", - source: { - droppableId: "custom-list-entries", - }, - }); - - wrapper.update(); - - let resultsContainer = wrapper.find(".custom-list-search-results"); - let resultsDroppable = resultsContainer.find(Droppable); - - expect(resultsDroppable.prop("isDropDisabled")).to.equal(false); - - let message = resultsDroppable.find("p"); - - expect(message.length).to.equal(1); - expect(message.text()).to.contain("here to remove"); - - // If the drop occurs anywhere on the page, the message goes away. - // Simulate dropping outside a droppable (no destination). - - const onDragEnd = dragDropContext.prop("onDragEnd"); - - onDragEnd({ - draggableId: "A", - source: { - droppableId: "custom-list-entries", - }, - }); - - wrapper.update(); - - resultsContainer = wrapper.find(".custom-list-search-results"); - resultsDroppable = resultsContainer.find(Droppable); - - expect(resultsDroppable.prop("isDropDisabled")).to.equal(true); - - message = resultsDroppable.find("p"); - - expect(message.length).to.equal(0); - }); - - it("calls deleteEntry when a book is dragged from list entries to search results", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - // Simulate starting a drag from list entries. - - const dragDropContext = wrapper.find(DragDropContext); - const onDragStart = dragDropContext.prop("onDragStart"); - - onDragStart({ - draggableId: "A", - source: { - droppableId: "custom-list-entries", - }, - }); - - wrapper.update(); - - const resultsContainer = wrapper.find(".custom-list-search-results"); - const resultsDroppable = resultsContainer.find(Droppable); - - expect(resultsDroppable.prop("isDropDisabled")).to.equal(false); - - // Simulate dropping on the search results. - - const onDragEnd = dragDropContext.prop("onDragEnd"); - - onDragEnd({ - draggableId: "A", - source: { - droppableId: "custom-list-entries", - }, - destination: { - droppableId: "search-results", - }, - }); - - wrapper.update(); - - expect(deleteEntry.callCount).to.equal(1); - expect(deleteEntry.args[0]).to.deep.equal(["A"]); - }); - - it("calls addEntry when the Add to List button is clicked on a search result", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const display = wrapper.find(".custom-list-entries h4"); - - expect(display.text()).to.equal( - "List Entries: Displaying 1 - 2 of 2 books" - ); - - const addButton = wrapper - .find(".custom-list-search-results .links") - .find(Button); - - addButton.at(0).simulate("click"); - - expect(addEntry.callCount).to.equal(1); - expect(addEntry.args[0]).to.deep.equal(["1"]); - }); - - it("hides the Add to List buttons when autoUpdate is true", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const addButton = wrapper - .find(".custom-list-search-results .links") - .find(Button); - - expect(addButton.length).to.equal(0); - }); - - it("calls deleteEntry when the Remove from List button is clicked on a list entry", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const display = wrapper.find(".custom-list-entries h4"); - - expect(display.text()).to.equal( - "List Entries: Displaying 1 - 2 of 2 books" - ); - - const deleteButton = wrapper - .find(".custom-list-entries .links") - .find(Button); - - deleteButton.at(0).simulate("click"); - - expect(deleteEntry.callCount).to.equal(1); - expect(deleteEntry.args[0]).to.deep.equal(["A"]); - }); - - it("does not render Remove from List buttons on a list entries when isOwner is false", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const deleteButtons = wrapper.find(".custom-list-entries .links button"); - - expect(deleteButtons.length).to.equal(0); - }); - - it("does not render the Add All to List button when there are no search results", () => { - const wrapper = shallow( - , - { context: fullContext, childContextTypes } - ); - - const button = wrapper.find(".add-all-button"); - - expect(button.length).to.equal(0); - }); - - it("does not render the Add All to List button when autoUpdate is true", () => { - const wrapper = shallow( - , - { context: fullContext, childContextTypes } - ); - - const button = wrapper.find(".add-all-button"); - - expect(button.length).to.equal(0); - }); - - it("does not render the Add All to List button when isOwner is false", () => { - const wrapper = shallow( - , - { context: fullContext, childContextTypes } - ); - - const button = wrapper.find(".add-all-button"); - - expect(button.length).to.equal(0); - }); - - it("calls addAllEntries when the Add All to List button is clicked", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const display = wrapper.find(".custom-list-entries h4"); - - expect(display.text()).to.equal( - "List Entries: Displaying 1 - 2 of 2 books" - ); - - const button = wrapper.find(".add-all-button").at(0); - - button.simulate("click"); - - expect(addAllEntries.callCount).to.equal(1); - }); - - it("does not render the Delete all button when there are no entries", () => { - const wrapper = shallow( - , - { context: fullContext, childContextTypes } - ); - - const button = wrapper.find(".delete-all-button"); - - expect(button.length).to.equal(0); - }); - - it("does not render the Delete all button when isOwner is false", () => { - const wrapper = shallow( - , - { context: fullContext, childContextTypes } - ); - - const button = wrapper.find(".delete-all-button"); - - expect(button.length).to.equal(0); - }); - - it("calls deleteAllEntries when the Delete all button is clicked", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const display = wrapper.find(".custom-list-entries h4"); - - expect(display.text()).to.equal( - "List Entries: Displaying 1 - 2 of 2 books" - ); - - const button = wrapper.find(".delete-all-button").at(0); - - button.simulate("click"); - - expect(deleteAllEntries.callCount).to.equal(1); - }); - - it("hides the Load More button in search results when loadMoreSearchResults is null", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const button = wrapper.find( - ".custom-list-search-results .load-more-button" - ); - - expect(button.length).to.equal(0); - }); - - it("hides the Load More button in search results when isFetchingSearchResults is true", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const button = wrapper.find( - ".custom-list-search-results .load-more-button" - ); - - expect(button.length).to.equal(0); - }); - - it("hides Load More button in list entries when loadMoreEntries is null", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const button = wrapper.find(".custom-list-entries .load-more-button"); - - expect(button.length).to.equal(0); - }); - - it("disables the Load More button when loading more search results", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - let button = wrapper - .find(".custom-list-search-results .load-more-button") - .hostNodes(); - - expect(button.length).to.equal(1); - expect(button.prop("disabled")).not.to.be.true; - - wrapper.setProps({ isFetchingMoreSearchResults: true }); - - button = wrapper - .find(".custom-list-search-results .load-more-button") - .hostNodes(); - - expect(button.length).to.equal(1); - expect(button.prop("disabled")).to.equal(true); - }); - - it("disables the Load More button when loading more list entries", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - let button = wrapper - .find(".custom-list-entries .load-more-button") - .hostNodes(); - - expect(button.length).to.equal(1); - expect(button.prop("disabled")).not.to.be.true; - - wrapper.setProps({ isFetchingMoreCustomListEntries: true }); - - button = wrapper.find(".custom-list-entries .load-more-button").hostNodes(); - - expect(button.length).to.equal(1); - expect(button.prop("disabled")).to.equal(true); - }); - - it("calls loadMoreSearchResults when the Load More button is clicked in search results", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const button = wrapper - .find(".custom-list-search-results .load-more-button") - .at(0); - - button.simulate("click"); - - expect(loadMoreSearchResults.callCount).to.equal(1); - }); - - it("calls loadMoreEntries when the Load More button is clicked in list entries", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const button = wrapper.find(".custom-list-entries .load-more-button").at(0); - - button.simulate("click"); - - expect(loadMoreEntries.callCount).to.equal(1); - }); - - it("should properly display the count of list entries", () => { - const wrapper = mount( - , - { context: fullContext, childContextTypes } - ); - - const display = wrapper.find(".custom-list-entries h4"); - - expect(display.text()).to.equal( - "List Entries: Displaying 1 - 2 of 2 books" - ); - - wrapper.setProps({ - entries: entriesData.slice(0, 1), - entryCount: 1, - }); - - expect(display.text()).to.equal("List Entries: Displaying 1 - 1 of 1 book"); - - wrapper.setProps({ - entries: [], - entryCount: 0, - }); - - expect(display.text()).to.equal("List Entries: No books in this list"); - - wrapper.setProps({ - entryCount: 12, - }); - - expect(display.text()).to.equal( - "List Entries: Displaying 0 - 0 of 12 books" - ); - - wrapper.setProps({ - entries: entriesData, - }); - - expect(display.text()).to.equal( - "List Entries: Displaying 1 - 2 of 12 books" - ); - }); -}); diff --git a/src/components/__tests__/CustomLists-test.tsx b/src/components/__tests__/CustomLists-test.tsx deleted file mode 100644 index 6763af875b..0000000000 --- a/src/components/__tests__/CustomLists-test.tsx +++ /dev/null @@ -1,805 +0,0 @@ -import { expect } from "chai"; -import { stub } from "sinon"; - -import * as React from "react"; -import { shallow, mount } from "enzyme"; - -import { CustomLists } from "../CustomLists"; -import ErrorMessage from "../ErrorMessage"; -import LoadingIndicator from "@thepalaceproject/web-opds-client/lib/components/LoadingIndicator"; -import CustomListEditor from "../CustomListEditor"; -import Admin from "../../models/Admin"; -import { LaneData } from "../../interfaces"; -import CustomListsSidebar from "../CustomListsSidebar"; -import * as navigate from "../../utils/navigate"; - -describe("CustomLists", () => { - let wrapper; - let fetchCustomLists; - let fetchCustomListDetails; - let deleteCustomList; - let openCustomListEditor; - let saveCustomListEditor; - let executeCustomListEditorSearch; - let loadMoreSearchResults; - let loadMoreEntries; - let fetchCollections; - let fetchLibraries; - let fetchLanes; - let fetchLanguages; - - const customListEditorProperties = { - name: "", - collections: [], - autoUpdate: false, - }; - - const customListEditorEntries = { - baseline: [], - baselineTotalCount: 0, - added: {}, - removed: {}, - current: [], - currentTotalCount: 0, - }; - - const customListEditorSearchParams = { - entryPoint: "All", - terms: "", - sort: null, - language: "all", - advanced: { - include: { - query: null, - selectedQueryId: null, - clearFilters: null, - }, - exclude: { - query: null, - selectedQueryId: null, - clearFilters: null, - }, - }, - }; - - const listsData = [ - { - id: 1, - name: "a list", - entry_count: 0, - collections: [], - is_owner: true, - is_shared: false, - }, - { - id: 2, - name: "z list", - entry_count: 1, - collections: [{ id: 3, name: "collection 3", protocol: "protocol" }], - is_owner: true, - is_shared: false, - }, - ]; - - const entry = { pwid: "1", title: "title", authors: [] }; - - const searchResults = { - id: "id", - url: "url", - title: "title", - lanes: [], - books: [], - navigationLinks: [], - nextPageUrl: "http://next.page", - }; - - const collections = [ - { - id: 1, - name: "collection 1", - protocol: "protocol", - libraries: [{ short_name: "other library" }], - }, - { - id: 2, - name: "collection 2", - protocol: "protocol", - libraries: [{ short_name: "library" }], - }, - { - id: 3, - name: "collection 3", - protocol: "protocol", - libraries: [{ short_name: "library" }], - }, - ]; - - const libraries = [ - { - short_name: "library", - settings: { - enabled_entry_points: ["Book", "Audio"], - }, - }, - { - short_name: "another library", - settings: { - enabled_entry_points: ["Audio"], - }, - }, - ]; - - const languages = { - eng: ["English"], - spa: ["Spanish", "Castilian"], - fre: ["French"], - }; - - const lane1: LaneData = { - id: 1, - display_name: "lane 1", - visible: false, - count: 1, - sublanes: [], - custom_list_ids: [2], - inherit_parent_restrictions: false, - }; - const lane2: LaneData = { - id: 2, - display_name: "lane 2", - visible: false, - count: 1, - sublanes: [], - custom_list_ids: [2], - inherit_parent_restrictions: false, - }; - const lane3: LaneData = { - id: 3, - display_name: "lane 2", - visible: false, - count: 1, - sublanes: [], - custom_list_ids: [], - inherit_parent_restrictions: false, - }; - const allLanes = [lane1, lane2, lane3]; - const lanesToDelete = [lane1, lane2]; - - const libraryManager = new Admin([{ role: "manager", library: "library" }]); - const librarian = new Admin([{ role: "librarian", library: "library" }]); - - describe("on mount", () => { - const listsUrl = "/admin/web/lists/library"; - let navigateTo; - let currentHref; - const lastNavigation = () => navigateTo.args[navigateTo.callCount - 1][0]; - - beforeEach(() => { - navigateTo = stub(navigate, "navigateTo"); - currentHref = stub(navigate, "currentHref").returns(listsUrl); - - fetchCustomLists = stub(); - openCustomListEditor = stub(); - fetchCustomListDetails = stub(); - saveCustomListEditor = stub().returns(Promise.resolve()); - deleteCustomList = stub().returns(Promise.resolve()); - executeCustomListEditorSearch = stub(); - loadMoreSearchResults = stub(); - loadMoreEntries = stub(); - fetchCollections = stub(); - fetchLibraries = stub(); - fetchLanes = stub().returns(Promise.resolve()); - fetchLanguages = stub(); - - wrapper = mount( - , - { context: { admin: libraryManager } } - ); - }); - - afterEach(() => { - navigateTo.restore(); - currentHref.restore(); - }); - - it("fetches libraries and languages", () => { - expect(fetchLibraries.callCount).to.equal(1); - expect(fetchLanguages.callCount).to.equal(1); - }); - - it("renders error message", () => { - let error = wrapper.find(ErrorMessage); - expect(error.length).to.equal(0); - - wrapper.setProps({ - fetchError: { status: 500, response: "Error", url: "url" }, - }); - error = wrapper.find(ErrorMessage); - expect(error.length).to.equal(1); - }); - - it("renders loading message", () => { - let loading = wrapper.find(LoadingIndicator); - expect(loading.length).to.equal(0); - - wrapper.setProps({ isFetching: true }); - loading = wrapper.find(LoadingIndicator); - expect(loading.length).to.equal(1); - }); - - it("navigates to create or edit page on initial load", () => { - wrapper = mount( - , - { context: { admin: libraryManager } } - ); - wrapper.setProps({ lists: [] }); - expect(lastNavigation()).to.equal(`${listsUrl}/create`); - - wrapper = mount( - , - { context: { admin: libraryManager } } - ); - wrapper.setProps({ lists: listsData }); - expect(lastNavigation()).to.equal(`${listsUrl}/edit/1`); - - // The create page should open if there are no owned lists. - - const noOwnedListsData = [ - { - id: 1, - name: "a list", - entry_count: 0, - collections: [], - is_owner: false, - is_shared: true, - }, - ]; - - wrapper = mount( - , - { context: { admin: libraryManager } } - ); - wrapper.setProps({ lists: noOwnedListsData }); - expect(lastNavigation()).to.equal(`${listsUrl}/create`); - }); - - it("sorts lists", () => { - wrapper = mount( - , - { context: { admin: libraryManager } } - ); - - let sidebar; - - sidebar = wrapper.find(CustomListsSidebar); - - expect(sidebar.prop("lists").map((list) => list.name)).to.deep.equal([ - "a list", - "z list", - ]); - - sidebar.invoke("changeSort")("desc"); - - sidebar = wrapper.find(CustomListsSidebar); - - expect(sidebar.prop("lists").map((list) => list.name)).to.deep.equal([ - "z list", - "a list", - ]); - - sidebar.invoke("changeSort")("asc"); - - sidebar = wrapper.find(CustomListsSidebar); - - expect(sidebar.prop("lists").map((list) => list.name)).to.deep.equal([ - "a list", - "z list", - ]); - }); - - it("filters lists", () => { - const sharedListsData = [ - { - id: 1, - name: "owned unshared", - entry_count: 0, - collections: [], - is_owner: true, - is_shared: false, - }, - { - id: 2, - name: "owned shared", - entry_count: 1, - collections: [{ id: 3, name: "collection 3", protocol: "protocol" }], - is_owner: true, - is_shared: true, - }, - { - id: 3, - name: "not owned", - entry_count: 1, - collections: [{ id: 3, name: "collection 3", protocol: "protocol" }], - is_owner: false, - is_shared: true, - }, - ]; - - wrapper = mount( - , - { context: { admin: libraryManager } } - ); - - let sidebar; - - sidebar = wrapper.find(CustomListsSidebar); - - expect(sidebar.prop("lists").map((list) => list.name)).to.deep.equal([ - "owned shared", - "owned unshared", - ]); - - sidebar.invoke("changeFilter")("shared-in"); - - sidebar = wrapper.find(CustomListsSidebar); - - expect(sidebar.prop("lists").map((list) => list.name)).to.deep.equal([ - "not owned", - ]); - - sidebar.invoke("changeFilter")("shared-out"); - - sidebar = wrapper.find(CustomListsSidebar); - - expect(sidebar.prop("lists").map((list) => list.name)).to.deep.equal([ - "owned shared", - ]); - - sidebar.invoke("changeFilter")(""); - - sidebar = wrapper.find(CustomListsSidebar); - - expect(sidebar.prop("lists").map((list) => list.name)).to.deep.equal([ - "not owned", - "owned shared", - "owned unshared", - ]); - - sidebar.invoke("changeFilter")("owned"); - - sidebar = wrapper.find(CustomListsSidebar); - - expect(sidebar.prop("lists").map((list) => list.name)).to.deep.equal([ - "owned shared", - "owned unshared", - ]); - }); - - it("renders edit link but does not render delete button for librarian", () => { - wrapper = mount( - , - { context: { admin: librarian } } - ); - const lists = wrapper.find("li"); - expect(lists.length).to.equal(2); - - const listAButtons = lists.at(0).find(".custom-list-buttons"); - const listAEditLink = listAButtons.find("Link"); - const listZButtons = lists.at(1).find(".custom-list-buttons"); - const listZEditLink = listZButtons.find("Link"); - expect(listAEditLink.length).to.equal(1); - expect(listAEditLink.text()).to.include("Edit"); - expect(listAEditLink.prop("to")).to.equal( - "/admin/web/lists/library/edit/1" - ); - expect(listZEditLink.length).to.equal(1); - expect(listZEditLink.text()).to.include("Edit"); - expect(listZEditLink.prop("to")).to.equal( - "/admin/web/lists/library/edit/2" - ); - - const listADeleteButton = listAButtons.find("button"); - const listZDeleteButton = listZButtons.find("button"); - expect(listADeleteButton.length).to.equal(0); - expect(listZDeleteButton.length).to.equal(0); - }); - - it("fetches lanes to be deleted", async () => { - let deletedLanes = await ( - wrapper.instance() as CustomLists - ).getDeletedLanes(listsData[1].id); - // There are no lanes so fetch them. - expect(fetchLanes.callCount).to.equal(1); - - // But now manually setting the lanes so the fetchLanes - // call count should still remain at 1. - wrapper.setProps({ lanes: allLanes }); - - deletedLanes = await (wrapper.instance() as CustomLists).getDeletedLanes( - listsData[1].id - ); - - expect(fetchLanes.callCount).to.equal(1); - expect(deletedLanes.length).to.equal(2); - expect(deletedLanes[0]).to.equal(lane1); - expect(deletedLanes[1]).to.equal(lane2); - }); - - it("outputs a list of lanes that will be deleted when a list is deleted", () => { - const prompt = (wrapper.instance() as CustomLists).deletedLaneNames( - lanesToDelete - ); - expect(prompt).to.equal( - "Deleting this list will delete the following lanes:\n" + - "\nLane name: lane 1\nLane name: lane 2" - ); - }); - - it("saves a list", async () => { - (wrapper.instance() as CustomLists).saveCustomListEditor(); - expect(saveCustomListEditor.callCount).to.equal(1); - }); - - it("renders create form", async () => { - let editor = wrapper.find(CustomListEditor); - expect(editor.length).to.equal(0); - - wrapper.setProps({ editOrCreate: "create" }); - editor = wrapper.find(CustomListEditor); - expect(editor.length).to.equal(1); - expect(editor.props().library).to.eql(libraries[0]); - expect(editor.props().list).to.be.undefined; - expect(editor.props().search).to.equal(executeCustomListEditorSearch); - expect(editor.props().loadMoreSearchResults).to.equal( - loadMoreSearchResults - ); - expect(editor.props().searchResults).to.equal(searchResults); - expect(editor.props().isFetchingMoreSearchResults).to.equal(false); - expect(editor.props().collections).to.deep.equal([ - collections[1], - collections[2], - ]); - expect(editor.props().languages).to.eql(languages); - - expect(fetchCustomLists.callCount).to.equal(1); - const save = editor.props().save; - await save(); - expect(saveCustomListEditor.callCount).to.equal(1); - expect(fetchCustomLists.callCount).to.equal(2); - }); - - it("renders edit form", () => { - let editor = wrapper.find(CustomListEditor); - expect(editor.length).to.equal(0); - - const listDetails = Object.assign({}, listsData[1], { entries: [entry] }); - wrapper.setProps({ editOrCreate: "edit", identifier: "2", listDetails }); - editor = wrapper.find(CustomListEditor); - expect(editor.length).to.equal(1); - expect(editor.props().library).to.eql(libraries[0]); - expect(editor.props().search).to.equal(executeCustomListEditorSearch); - expect(editor.props().loadMoreSearchResults).to.equal( - loadMoreSearchResults - ); - expect(editor.props().searchResults).to.equal(searchResults); - expect(editor.props().isFetchingMoreSearchResults).to.equal(false); - expect(editor.props().collections).to.deep.equal([ - collections[1], - collections[2], - ]); - expect(editor.props().languages).to.eql(languages); - - expect(fetchCustomListDetails.callCount).to.equal(1); - - // When the component switches to a different list, it fetches the new - // list details. - wrapper.setProps({ identifier: "1" }); - expect(fetchCustomListDetails.callCount).to.equal(2); - }); - - it("gets the correct entry points list from the right library", () => { - const entryPoints = wrapper.instance().getEnabledEntryPoints(libraries); - - expect(entryPoints.length).to.equal(2); - expect(entryPoints).to.eql(["Book", "Audio"]); - }); - - it("gets the correct entry points list from the second available library", () => { - wrapper = mount( - , - { context: { admin: librarian } } - ); - - const entryPoints = wrapper.instance().getEnabledEntryPoints(libraries); - - expect(entryPoints.length).to.equal(1); - expect(entryPoints).to.eql(["Audio"]); - }); - }); - - // These tests are for mocking the confirm function in the window object. - // It reliably works when shallow mounting a component but not when doing a - // full mount. Seems to be a problem with Node v10+. - describe("on shallow mount", () => { - let confirmStub; - let listDataSort; - let deleteCustomListFn; - - beforeEach(() => { - confirmStub = stub(window, "confirm"); - fetchCustomLists = stub(); - openCustomListEditor = stub(); - fetchCustomListDetails = stub(); - saveCustomListEditor = stub().returns(Promise.resolve()); - deleteCustomList = stub().returns(Promise.resolve()); - executeCustomListEditorSearch = stub(); - loadMoreSearchResults = stub(); - loadMoreEntries = stub(); - fetchCollections = stub(); - fetchLibraries = stub(); - fetchLanes = stub().returns(Promise.resolve()); - - wrapper = shallow( - , - { context: { admin: librarian } } - ); - - deleteCustomListFn = (wrapper.instance() as CustomLists).deleteCustomList; - listDataSort = (wrapper.instance() as CustomLists).filteredSortedLists( - listsData - ); - }); - - afterEach(() => { - confirmStub.restore(); - }); - - // Ideally, the test would click on the button that calls the - // `deleteCustomList` function which in turn calls the `deleteCustomList` - // prop. Instead, call the instance's `deleteCustomList` function directly, - // and check if the prop was called and with what arguments. - it("deletes a list", async () => { - confirmStub.returns(false); - const getDeletedLanes = stub( - wrapper.instance() as CustomLists, - "getDeletedLanes" - ).returns(Promise.resolve()); - - // The instance's `deleteCustomList` function needs a CustomListData - // list which is one sorted object from full list of lists. The first - // list corresponds to the "button". - await deleteCustomListFn(listDataSort[0]); - expect(deleteCustomList.callCount).to.equal(0); - - confirmStub.returns(true); - - await deleteCustomListFn(listDataSort[0]); - expect(deleteCustomList.callCount).to.equal(1); - expect(deleteCustomList.args[0][0]).to.equal("1"); - - getDeletedLanes.restore(); - }); - - it("deletes a list and warns of lanes that will be deleted", async () => { - wrapper.setProps({ lanes: allLanes }); - - confirmStub.returns(true); - - await deleteCustomListFn(listDataSort[0]); - // prettier-ignore - expect(confirmStub.args[0][0]).to.equal("Delete list \"a list\"? "); - - // Continuining from the previous test, this second list corresponds - // to the second "button" that is being clicked. - await deleteCustomListFn(listDataSort[1]); - // prettier-ignore - expect(confirmStub.args[1][0]).to.equal("Delete list \"z list\"? " + - "Deleting this list will delete the following lanes:\n" + - "\nLane name: lane 1\nLane name: lane 2" - ); - }); - }); -}); diff --git a/src/components/__tests__/InputList-test.tsx b/src/components/__tests__/InputList-test.tsx deleted file mode 100644 index 1b1168b374..0000000000 --- a/src/components/__tests__/InputList-test.tsx +++ /dev/null @@ -1,509 +0,0 @@ -import { expect } from "chai"; -import * as React from "react"; -import { mount } from "enzyme"; -import { stub, spy } from "sinon"; -import { Button } from "library-simplified-reusable-components"; -import buildStore from "../../store"; - -import InputList from "../InputList"; -import ProtocolFormField from "../ProtocolFormField"; -import EditableInput from "../EditableInput"; -import WithRemoveButton from "../WithRemoveButton"; -import ToolTip from "../ToolTip"; -import LanguageField from "../LanguageField"; - -describe("InputList", () => { - let wrapper; - let store; - let context; - const value = ["Thing 1", "Thing 2"]; - const setting = { - key: "setting", - label: "label", - description: "description", - type: "list", - }; - let parent; - let createEditableInput; - let labelAndDescription; - - beforeEach(() => { - store = buildStore(); - context = { editorStore: store }; - parent = mount(); - createEditableInput = spy(parent.instance(), "createEditableInput"); - labelAndDescription = spy(parent.instance(), "labelAndDescription"); - - wrapper = mount( - , - { context } - ); - }); - - it("renders a label and description", () => { - expect(labelAndDescription.callCount).to.equal(1); - expect(labelAndDescription.args[0][0]).to.deep.equal(setting); - const label = wrapper.find("label"); - expect(label.length).to.equal(1); - expect(label.text()).to.equal("label"); - - const description = wrapper.find(".description").at(0); - expect(description.text()).to.equal("description"); - }); - - it("renders a list of items", () => { - const inputs = wrapper.find(".form-control"); - expect(inputs.length).to.equal(3); - expect(inputs.at(0).prop("value")).to.equal("Thing 1"); - expect(inputs.at(0).prop("type")).to.equal("text"); - expect(inputs.at(0).prop("name")).to.equal("setting"); - - expect(inputs.at(1).prop("value")).to.equal("Thing 2"); - expect(inputs.at(1).prop("type")).to.equal("text"); - expect(inputs.at(1).prop("name")).to.equal("setting"); - - expect(inputs.at(2).prop("value")).to.equal(""); - expect(inputs.at(2).prop("type")).to.equal("text"); - expect(inputs.at(2).prop("name")).to.equal("setting"); - - expect(createEditableInput.callCount).to.equal(3); - }); - - it("optionally renders links", () => { - const urlBase = (itemName) => { - return `admin/web/${itemName}`; - }; - const settingWithUrlBase = { ...setting, ...{ urlBase } }; - wrapper.setProps({ setting: settingWithUrlBase }); - const links = wrapper.find("a"); - expect(links.length).to.equal(2); - links.forEach((l, idx) => { - expect(l.text()).to.equal(`Thing ${idx + 1}`); - expect(l.prop("href")).to.equal(`admin/web/Thing ${idx + 1}`); - }); - }); - - it("renders WithRemoveButton elements", () => { - const withRemoveButtons = wrapper.find(WithRemoveButton); - expect(withRemoveButtons.length).to.equal(2); - expect(withRemoveButtons.at(0).prop("disabled")).to.be.false; - expect(withRemoveButtons.at(0).find("input").prop("value")).to.equal( - "Thing 1" - ); - expect(withRemoveButtons.at(1).prop("disabled")).to.be.false; - expect(withRemoveButtons.at(1).find("input").prop("value")).to.equal( - "Thing 2" - ); - }); - - it("optionally disables the remove buttons", () => { - wrapper.setProps({ disableButton: true }); - const withRemoveButtons = wrapper.find(WithRemoveButton); - expect(withRemoveButtons.length).to.equal(2); - expect(withRemoveButtons.at(0).prop("disabled")).to.be.true; - expect(withRemoveButtons.at(0).find("button").prop("disabled")).to.be.true; - expect(withRemoveButtons.at(1).prop("disabled")).to.be.true; - expect(withRemoveButtons.at(1).find("button").prop("disabled")).to.be.true; - }); - - it("renders a button for adding a list item", () => { - const addListItemContainer = wrapper.find(".add-list-item-container"); - const addListItem = addListItemContainer.find("span.add-list-item"); - expect(addListItem.length).to.equal(1); - expect(addListItem.find("input").prop("value")).to.equal(""); - expect(addListItemContainer.find(WithRemoveButton).length).to.equal(0); - expect(addListItemContainer.find("button.add-list-item").text()).to.equal( - "Add" - ); - }); - - it("optionally renders a geographic tooltip with extra content", () => { - const valueWithObject = [{ "Thing 3": "extra information!" }]; - const geographicSetting = { ...setting, ...{ format: "geographic" } }; - const spyToolTip = spy(wrapper.instance(), "renderToolTip"); - - wrapper.setProps({ setting: geographicSetting, value: valueWithObject }); - - const withAddOn = wrapper.find(".with-add-on"); - expect(withAddOn.length).to.equal(1); - - const addOn = withAddOn.find(".input-group-addon"); - expect(addOn.length).to.equal(1); - const toolTipElement = addOn.find(ToolTip); - expect(toolTipElement.length).to.equal(1); - expect(toolTipElement.find("svg").hasClass("locatorIcon")).to.be.true; - expect(toolTipElement.find(".tool-tip").hasClass("point-right")).to.be.true; - expect(toolTipElement.find(".tool-tip").text()).to.equal( - "extra information!" - ); - - expect(withAddOn.find("input").length).to.equal(1); - expect(withAddOn.find("input").prop("value")).to.equal("Thing 3"); - expect(spyToolTip.args[0]).to.eql([valueWithObject[0], "geographic"]); - }); - - it("renders an autocomplete field for languages", () => { - const valueWithObject = ["abc"]; - const languageSetting = { ...setting, ...{ format: "language-code" } }; - const languages = { - eng: ["English"], - spa: ["Spanish", "Castilian"], - }; - wrapper.setProps({ - setting: languageSetting, - value: valueWithObject, - additionalData: languages, - }); - const languageField = wrapper.find(LanguageField); - expect(languageField.length).to.equal(2); - - expect(languageField.at(0).prop("value")).to.equal("abc"); - expect(languageField.at(0).prop("name")).to.equal("setting"); - expect(languageField.at(0).prop("languages")).to.equal(languages); - - expect(languageField.at(1).prop("value")).to.be.undefined; - expect(languageField.at(1).prop("name")).to.equal("setting"); - expect(languageField.at(1).prop("languages")).to.equal(languages); - }); - - it("removes an item", () => { - let removables = wrapper.find(WithRemoveButton); - expect(removables.length).to.equal(2); - const button = removables.at(0).find(".remove-btn").hostNodes(); - button.simulate("click"); - removables = wrapper.find(WithRemoveButton); - expect(removables.length).to.equal(1); - }); - - it("adds a regular item", async () => { - let removables = wrapper.find(WithRemoveButton); - expect(removables.length).to.equal(2); - - let blankInput = wrapper.find("span.add-list-item input"); - blankInput.getDOMNode().value = "Another thing..."; - blankInput.simulate("change"); - const addButton = wrapper.find("button.add-list-item"); - addButton.simulate("click"); - await new Promise((resolve) => setTimeout(resolve, 0)); - - wrapper.update(); - removables = wrapper.find(WithRemoveButton); - expect(removables.length).to.equal(3); - - blankInput = wrapper.find("span.add-list-item input"); - expect(blankInput.prop("value")).to.equal(""); - }); - - it("adds and capitalizes an item", async () => { - wrapper.setProps({ - setting: { ...wrapper.prop("setting"), ...{ capitalize: true } }, - }); - let removables = wrapper.find(WithRemoveButton); - expect(removables.length).to.equal(2); - - let blankInput = wrapper.find("span.add-list-item input"); - blankInput.getDOMNode().value = "new york"; - blankInput.simulate("change"); - const addButton = wrapper.find("button.add-list-item"); - addButton.simulate("click"); - await new Promise((resolve) => setTimeout(resolve, 0)); - - wrapper.update(); - removables = wrapper.find(WithRemoveButton); - expect(removables.length).to.equal(3); - expect(removables.at(2).find(EditableInput).prop("value")).to.equal( - "New York" - ); - expect(wrapper.state()["listItems"][2]).to.equal("New York"); - - blankInput = wrapper.find("span.add-list-item input"); - expect(blankInput.prop("value")).to.equal(""); - }); - - it("capitalizes a string", () => { - wrapper.setProps({ - setting: { ...wrapper.prop("setting"), ...{ format: "geographic" } }, - }); - const cap = wrapper.instance().capitalize; - // Capitalizes one word - expect(cap("california")).to.equal("California"); - // Capitalizes multiple words - expect(cap("new jersey")).to.equal("New Jersey"); - // Capitalizes two-letter state/province abbreviations - expect(cap("fl")).to.equal("FL"); - // Handles mixed words and abbreviations - expect(cap("new york city, ny")).to.equal("New York City, NY"); - }); - - it("adds an autocompleted item", async () => { - const languageSetting = { ...setting, format: "language-code" }; - wrapper.setProps({ setting: languageSetting, value: ["abc"] }); - - let removables = wrapper.find(WithRemoveButton); - expect(removables.length).to.equal(1); - let autocomplete = wrapper - .find("input[list='setting-autocomplete-list']") - .at(1); - autocomplete.getDOMNode().value = "Another language"; - autocomplete.simulate("change"); - const addButton = wrapper.find("button.add-list-item"); - addButton.simulate("click"); - await new Promise((resolve) => setTimeout(resolve, 0)); - wrapper.update(); - - removables = wrapper.find(WithRemoveButton); - expect(removables.length).to.equal(2); - autocomplete = wrapper - .find("input[list='setting-autocomplete-list']") - .at(2); - expect(autocomplete.prop("value")).to.equal(""); - }); - - it("does not add an empty input item", () => { - let removables = wrapper.find(WithRemoveButton); - expect(removables.length).to.equal(2); - expect(wrapper.state()["newItem"]).to.equal(""); - - let addButton = wrapper.find("button.add-list-item"); - expect(addButton.prop("disabled")).to.be.true; - addButton.simulate("click"); - removables = wrapper.find(WithRemoveButton); - expect(removables.length).to.equal(2); - - const empty = wrapper.find("span.add-list-item input"); - empty.getDOMNode().value = "something new"; - empty.simulate("change"); - addButton = wrapper.find("button.add-list-item"); - expect(wrapper.state()["newItem"]).to.equal("something new"); - expect(addButton.prop("disabled")).not.to.be.true; - addButton.simulate("click"); - - removables = wrapper.find(WithRemoveButton); - addButton = wrapper.find("button.add-list-item"); - expect(removables.length).to.equal(3); - expect(addButton.prop("disabled")).to.be.true; - }); - - it("optionally accepts an onChange prop", async () => { - const onChange = stub(); - wrapper.setProps({ onChange }); - expect(onChange.callCount).to.equal(0); - wrapper.instance().addListItem(); - await new Promise((resolve) => setTimeout(resolve, 0)); - expect(onChange.callCount).to.equal(1); - expect(onChange.args[0][0]).to.equal(wrapper.state()); - wrapper.instance().removeListItem("test"); - await new Promise((resolve) => setTimeout(resolve, 0)); - expect(onChange.callCount).to.equal(2); - expect(onChange.args[1][0]).to.equal(wrapper.state()); - }); - - it("optionally accepts a readOnly prop", () => { - wrapper.setProps({ readOnly: true }); - expect(wrapper.find(EditableInput).at(0).prop("readOnly")).to.be.true; - expect(wrapper.find(EditableInput).at(1).prop("readOnly")).to.be.true; - }); - - it("gets the value", () => { - expect((wrapper.instance() as InputList).getValue()).to.eql(value); - }); - - it("clears all the items", () => { - let removables = wrapper.find(WithRemoveButton); - expect(removables.length).to.equal(2); - - (wrapper.instance() as InputList).clear(); - wrapper.update(); - removables = wrapper.find(WithRemoveButton); - expect(removables.length).to.equal(0); - }); - describe("dropdown menu", () => { - let options; - beforeEach(() => { - options = []; - while (options.length < 3) { - const optionName = `Option ${options.length + 1}`; - options.push( - - ); - } - const menuSetting = { - ...setting, - ...{ type: "menu", menuOptions: options, description: null }, - }; - wrapper = mount( - , - { context } - ); - }); - it("renders a dropdown menu", () => { - const menu = wrapper.find("select"); - expect(menu.length).to.equal(1); - const menuOptions = menu.find("option"); - expect(menuOptions.length).to.equal(3); - menuOptions.forEach((o, idx) => { - expect(o.text()).to.equal(`Option ${idx + 1}`); - }); - }); - it("adds an item from the menu", () => { - let removables = wrapper.find(WithRemoveButton); - expect(removables.length).to.equal(2); - expect(wrapper.state()["listItems"].includes("Option 1")).to.be.false; - const menu = wrapper.find("select"); - expect(menu.getDOMNode().value).to.equal("Option 1"); - const addButton = wrapper.find(Button).last(); - addButton.simulate("click"); - removables = wrapper.find(WithRemoveButton); - expect(removables.length).to.equal(3); - expect(removables.last().find(EditableInput).prop("value")).to.equal( - "Option 1" - ); - expect(wrapper.state()["listItems"].includes("Option 1")).to.be.true; - }); - it("doesn't lose options when nothing is selected", () => { - const setting = { - ...wrapper.prop("setting"), - ...{ type: "menu", default: null, format: "narrow" }, - }; - wrapper = mount( - , - { context } - ); - const options = wrapper.find("option"); - expect(options.length).to.equal(3); - }); - it("optionally eliminates already-selected options from the menu", () => { - let options = wrapper.find("option"); - expect(options.length).to.equal(3); - expect(options.map((o) => o.text()).includes("Option 1")).to.be.true; - wrapper.find(Button).last().simulate("click"); - options = wrapper.find("option"); - expect(options.length).to.equal(3); - expect(options.map((o) => o.text()).includes("Option 1")).to.be.true; - - const narrowSetting = { - ...wrapper.prop("setting"), - ...{ format: "narrow" }, - }; - wrapper.setProps({ setting: narrowSetting }); - - wrapper.find(Button).last().simulate("click"); - options = wrapper.find("option"); - expect(options.length).to.equal(2); - expect(options.map((o) => o.text()).includes("Option 1")).to.be.false; - }); - it("optionally renders a label", () => { - const settingWithLabel = { - ...wrapper.prop("setting"), - ...{ menuTitle: "Custom Menu Title" }, - }; - wrapper.setProps({ setting: settingWithLabel }); - const label = wrapper.find("select").closest("label"); - expect(label.text()).to.contain("Custom Menu Title"); - }); - it("optionally marks the menu as required", () => { - let requiredText = wrapper.find(".required-field"); - expect(requiredText.length).to.equal(0); - const requiredSetting = { - ...wrapper.prop("setting"), - ...{ menuTitle: "title", required: true }, - }; - wrapper.setProps({ setting: requiredSetting }); - requiredText = wrapper.find(".required-field"); - expect(requiredText.length).to.equal(1); - expect(requiredText.text()).to.equal("Required"); - }); - it("optionally renders an alternate value if there are no list items", () => { - let placeholder = wrapper.find(".input-list > span"); - expect(placeholder.length).to.equal(0); - wrapper.setProps({ altValue: "No list items!" }); - placeholder = wrapper.find(".input-list > span"); - // There are still list items, so the placeholder isn't rendered yet. - expect(placeholder.length).to.equal(0); - wrapper.setProps({ value: [] }); - placeholder = wrapper.find(".input-list > span"); - expect(placeholder.length).to.equal(1); - expect(placeholder.text()).to.equal("No list items!"); - }); - it("optionally renders an alternate value if all the available list items have already been added", () => { - wrapper.setProps({ - value: ["Option 1", "Option 2", "Option 3"], - onEmpty: "You've run out of options!", - setting: { ...wrapper.prop("setting"), ...{ format: "narrow" } }, - }); - wrapper.update(); - const menu = wrapper.find("select"); - expect(menu.length).to.equal(0); - const message = wrapper.find(".add-list-item-container span"); - expect(message.text()).to.equal("You've run out of options!"); - }); - it("renders option elements if necessary", () => { - // If the setting does not have a menuOptions property (e.g. because it has come from the server without being modified), - // InputList will use its options property to generate the dropdown menu with basic default values. - const options = [ - { key: "key_1", label: "label_1" }, - { key: "key_2", label: "label_2" }, - ]; - const setting = { - ...wrapper.prop("setting"), - ...{ options: options, menuOptions: null }, - }; - wrapper = mount( - , - { context } - ); - const select = wrapper.find("select"); - expect(select.length).to.equal(1); - expect(select.find("option").at(0).prop("value")).to.equal("key_1"); - expect(select.find("option").at(0).text()).to.equal("label_1"); - expect(select.find("option").at(1).prop("value")).to.equal("key_2"); - expect(select.find("option").at(1).text()).to.equal("label_2"); - }); - it("renders the default values", () => { - const setting = { - ...wrapper.prop("setting"), - ...{ default: ["Option 1", "Option 2"] }, - }; - wrapper = mount( - , - { context } - ); - const defaultItems = wrapper.find(EditableInput); - expect(defaultItems.length).to.equal(3); - expect(defaultItems.at(0).prop("value")).to.equal("Option 1"); - expect(defaultItems.at(1).prop("value")).to.equal("Option 2"); - }); - }); -}); diff --git a/src/components/__tests__/LaneCustomListsEditor-test.tsx b/src/components/__tests__/LaneCustomListsEditor-test.tsx deleted file mode 100644 index 9ab1928c49..0000000000 --- a/src/components/__tests__/LaneCustomListsEditor-test.tsx +++ /dev/null @@ -1,504 +0,0 @@ -import { expect } from "chai"; -import { stub } from "sinon"; - -import * as React from "react"; -import { mount } from "enzyme"; - -import { Droppable, Draggable } from "react-beautiful-dnd"; -import LaneCustomListsEditor from "../LaneCustomListsEditor"; -import ShareIcon from "../icons/ShareIcon"; - -describe("LaneCustomListsEditor", () => { - let onUpdate; - - const allCustomListsData = [ - { id: 1, name: "list 1", entry_count: 0, is_owner: true, is_shared: false }, - { id: 2, name: "list 2", entry_count: 2, is_owner: true, is_shared: false }, - { id: 3, name: "list 3", entry_count: 0, is_owner: true, is_shared: false }, - ]; - - beforeEach(() => { - onUpdate = stub(); - }); - - it("renders available lists", () => { - const filteredCustomListsData = [ - allCustomListsData[0], - allCustomListsData[2], - ]; - - let wrapper = mount( - - ); - let container = wrapper.find(".available-lists"); - expect(container.length).to.equal(1); - - let droppable = container.find(Droppable); - expect(droppable.length).to.equal(1); - - let lists = droppable.find(Draggable); - expect(lists.length).to.equal(2); - - expect(lists.at(0).text()).to.contain("list 1"); - expect(lists.at(0).text()).to.contain("Items in list: 0"); - expect(lists.at(1).text()).to.contain("list 3"); - expect(lists.at(1).text()).to.contain("Items in list: 0"); - - wrapper = mount( - - ); - - container = wrapper.find(".available-lists"); - expect(container.length).to.equal(1); - - droppable = container.find(Droppable); - expect(droppable.length).to.equal(1); - - lists = droppable.find(Draggable); - expect(lists.length).to.equal(1); - - expect(lists.at(0).text()).to.contain("list 3"); - expect(lists.at(0).text()).to.contain("Items in list: 0"); - }); - - it("renders a share icon on available lists that are not owned by the current library", () => { - const sharedCustomListsData = [ - ...allCustomListsData, - { - id: 4, - name: "list 4", - entry_count: 0, - is_owner: false, - is_shared: true, - }, - ]; - - const wrapper = mount( - - ); - - const lists = wrapper.find(".available-lists").find(Draggable); - - expect(lists.length).to.equal(4); - - expect(lists.at(0).find(ShareIcon).length).to.equal(0); - expect(lists.at(1).find(ShareIcon).length).to.equal(0); - expect(lists.at(2).find(ShareIcon).length).to.equal(0); - expect(lists.at(3).find(ShareIcon).length).to.equal(1); - }); - - it("renders filter select", () => { - const changeFilter = stub(); - - const wrapper = mount( - - ); - - const select = wrapper.find('select[name="filter"]'); - - expect(select.prop("value")).to.equal("owned"); - - const options = select.find("option"); - - expect(options.length).to.equal(3); - - expect(options.at(0).prop("value")).to.equal(""); - expect(options.at(1).prop("value")).to.equal("owned"); - expect(options.at(2).prop("value")).to.equal("shared-in"); - - select.getDOMNode().value = "shared-in"; - select.simulate("change"); - - expect(changeFilter.callCount).to.equal(1); - expect(changeFilter.args[0]).to.deep.equal(["shared-in"]); - }); - - it("renders current lists", () => { - let wrapper = mount( - - ); - let container = wrapper.find(".current-lists"); - expect(container.length).to.equal(1); - - let droppable = container.find(Droppable); - expect(droppable.length).to.equal(1); - - let lists = droppable.find(Draggable); - expect(lists.length).to.equal(0); - - wrapper = mount( - - ); - - container = wrapper.find(".current-lists"); - expect(container.length).to.equal(1); - - droppable = container.find(Droppable); - expect(droppable.length).to.equal(1); - - lists = droppable.find(Draggable); - expect(lists.length).to.equal(2); - - expect(lists.at(0).text()).to.contain("list 2"); - expect(lists.at(0).text()).to.contain("Items in list: 2"); - expect(lists.at(1).text()).to.contain("list 3"); - expect(lists.at(1).text()).to.contain("Items in list: 0"); - }); - - it("renders a share icon on current lists that are not owned by the current library", () => { - const sharedCustomListsData = [ - ...allCustomListsData, - { - id: 4, - name: "list 4", - entry_count: 0, - is_owner: false, - is_shared: true, - }, - ]; - - const wrapper = mount( - - ); - - const lists = wrapper.find(".current-lists").find(Draggable); - - expect(lists.length).to.equal(2); - - expect(lists.at(0).find(ShareIcon).length).to.equal(0); - expect(lists.at(1).find(ShareIcon).length).to.equal(1); - }); - - it("prevents dragging within available lists", () => { - const wrapper = mount( - - ); - - // simulate starting a drag from available lists - (wrapper.instance() as LaneCustomListsEditor).onDragStart({ - draggableId: 1, - source: { - droppableId: "available-lists", - }, - }); - - const container = wrapper.find(".available-lists"); - const droppable = container.find(Droppable); - expect(droppable.prop("isDropDisabled")).to.equal(true); - }); - - it("prevents dragging within current lists", () => { - const wrapper = mount( - - ); - - // simulate starting a drag from current lists - (wrapper.instance() as LaneCustomListsEditor).onDragStart({ - draggableId: 1, - source: { - droppableId: "current-lists", - }, - }); - - const container = wrapper.find(".current-lists"); - const droppable = container.find(Droppable); - expect(droppable.prop("isDropDisabled")).to.equal(true); - }); - - it("drags from available lists to current lists", () => { - const wrapper = mount( - - ); - - // simulate starting a drag from available lists - (wrapper.instance() as LaneCustomListsEditor).onDragStart({ - draggableId: 2, - source: { - droppableId: "available-lists", - }, - }); - wrapper.update(); - - let currentContainer = wrapper.find(".current-lists"); - let droppable = currentContainer.find(Droppable); - expect(droppable.prop("isDropDisabled")).to.equal(false); - - // simulate dropping on the current lists - (wrapper.instance() as LaneCustomListsEditor).onDragEnd({ - draggableId: 2, - source: { - droppableId: "available-lists", - }, - destination: { - droppableId: "current-lists", - }, - }); - wrapper.update(); - - currentContainer = wrapper.find(".current-lists"); - droppable = currentContainer.find(Droppable); - // The dropped item has been added to the current lists. - const lists = droppable.find(Draggable); - expect(lists.length).to.equal(2); - expect(lists.at(0).text()).to.contain("list 1"); - expect(lists.at(1).text()).to.contain("list 2"); - expect(onUpdate.callCount).to.equal(1); - expect(onUpdate.args[0][0]).to.deep.equal([1, 2]); - }); - - it("shows message in place of available lists when dragging from current lists", () => { - const wrapper = mount( - - ); - - // simulate starting a drag from current lists - (wrapper.instance() as LaneCustomListsEditor).onDragStart({ - draggableId: 1, - source: { - droppableId: "current-lists", - }, - }); - wrapper.update(); - - let availableContainer = wrapper.find(".available-lists"); - let droppable = availableContainer.find(Droppable); - let message = droppable.find("p"); - expect(droppable.prop("isDropDisabled")).to.equal(false); - expect(message.length).to.equal(1); - expect(message.text()).to.contain("here to remove"); - - // if you drop anywhere on the page, the mssage goes away. - // simulate dropping outside a droppable (no destination) - (wrapper.instance() as LaneCustomListsEditor).onDragEnd({ - draggableId: 1, - source: { - droppableId: "current-lists", - }, - }); - wrapper.update(); - - availableContainer = wrapper.find(".available-lists"); - droppable = availableContainer.find(Droppable); - message = droppable.find("p"); - expect(droppable.prop("isDropDisabled")).to.equal(true); - expect(message.length).to.equal(0); - }); - - it("drags from current lists to available lists", () => { - const wrapper = mount( - - ); - - // simulate starting a drag from current lists - (wrapper.instance() as LaneCustomListsEditor).onDragStart({ - draggableId: 1, - source: { - droppableId: "current-lists", - }, - }); - wrapper.update(); - - const availableContainer = wrapper.find(".available-lists"); - let droppable = availableContainer.find(Droppable); - expect(droppable.prop("isDropDisabled")).to.equal(false); - - // simulate dropping on the available lists - (wrapper.instance() as LaneCustomListsEditor).onDragEnd({ - draggableId: 1, - source: { - droppableId: "current-lists", - }, - destination: { - droppableId: "available-lists", - }, - }); - wrapper.update(); - wrapper.setProps({ customListIds: onUpdate.args[0][0] }); - - // the dropped item has been removed from the current lists - const currentContainer = wrapper.find(".current-lists"); - droppable = currentContainer.find(Droppable); - const lists = droppable.find(Draggable); - - expect(lists.length).to.equal(1); - expect(lists.at(0).text()).to.contain("list 2"); - expect(onUpdate.callCount).to.equal(1); - expect(onUpdate.args[0][0]).to.deep.equal([2]); - }); - - it("adds a list to the lane", () => { - const wrapper = mount( - - ); - - const addLink = wrapper.find(".available-lists .links button"); - addLink.at(0).simulate("click"); - - // the item has been added to the current lists - const currentContainer = wrapper.find(".current-lists"); - const droppable = currentContainer.find(Droppable); - const lists = droppable.find(Draggable); - expect(lists.length).to.equal(2); - expect(lists.at(0).text()).to.contain("list 1"); - expect(onUpdate.callCount).to.equal(1); - expect(onUpdate.args[0][0]).to.contain(1); - expect(onUpdate.args[0][0]).to.contain(2); - }); - - it("removes a list from the lane", () => { - const wrapper = mount( - - ); - - const deleteLink = wrapper.find(".current-lists .links button"); - deleteLink.at(0).simulate("click"); - wrapper.setProps({ customListIds: onUpdate.args[0][0] }); - // this list has been removed from the current lists - const currentContainer = wrapper.find(".current-lists"); - const droppable = currentContainer.find(Droppable); - const lists = droppable.find(Draggable); - expect(lists.length).to.equal(1); - expect(lists.at(0).text()).to.contain("list 2"); - expect(onUpdate.callCount).to.equal(1); - expect(onUpdate.args[0][0]).to.deep.equal([2]); - }); - - it("resets", () => { - const wrapper = mount( - - ); - - // simulate dropping a list on the current lists - (wrapper.instance() as LaneCustomListsEditor).onDragEnd({ - draggableId: 2, - source: { - droppableId: "available-lists", - }, - destination: { - droppableId: "current-lists", - }, - }); - - // Set customListIds to the new array of list IDs for this lane ([1, 2]), which got passed to - // onUpdate when we added list 2 to the current lists - wrapper.setProps({ customListIds: onUpdate.args[0][0] }); - expect( - (wrapper.instance() as LaneCustomListsEditor).getCustomListIds().length - ).to.equal(2); - expect(onUpdate.callCount).to.equal(1); - (wrapper.instance() as LaneCustomListsEditor).reset([1]); - // Calling reset passes the original array of list IDs ([1]) to onUpdate - wrapper.setProps({ customListIds: onUpdate.args[1][0] }); - expect( - (wrapper.instance() as LaneCustomListsEditor).getCustomListIds().length - ).to.equal(1); - expect(onUpdate.callCount).to.equal(2); - - // simulate dropping a list on the available lists - (wrapper.instance() as LaneCustomListsEditor).onDragEnd({ - draggableId: 1, - source: { - droppableId: "current-lists", - }, - destination: { - droppableId: "available-lists", - }, - }); - - // Set customListIds to the new array of list IDs for this lane ([]), which got passed to - // onUpdate when we removed list 1 from the current lists - wrapper.setProps({ customListIds: onUpdate.args[2][0] }); - expect( - (wrapper.instance() as LaneCustomListsEditor).getCustomListIds().length - ).to.equal(0); - expect(onUpdate.callCount).to.equal(3); - (wrapper.instance() as LaneCustomListsEditor).reset([1]); - // Calling reset passes the original array of list IDs ([1]) to onUpdate - wrapper.setProps({ customListIds: onUpdate.args[3][0] }); - expect( - (wrapper.instance() as LaneCustomListsEditor).getCustomListIds().length - ).to.equal(1); - expect(onUpdate.callCount).to.equal(4); - }); -}); diff --git a/src/components/__tests__/PairedMenus-test.tsx b/src/components/__tests__/PairedMenus-test.tsx deleted file mode 100644 index a162d2c5e5..0000000000 --- a/src/components/__tests__/PairedMenus-test.tsx +++ /dev/null @@ -1,184 +0,0 @@ -import { expect } from "chai"; -import { spy } from "sinon"; - -import * as React from "react"; -import { mount } from "enzyme"; -import PairedMenus from "../PairedMenus"; -import InputList from "../InputList"; - -describe("PairedMenus", () => { - let wrapper; - let inputListSetting; - let dropdownSetting; - beforeEach(() => { - inputListSetting = { - key: "input", - label: "Input List", - default: ["a", "b", "c"], - options: [ - { key: "a", label: "A" }, - { key: "b", label: "B" }, - { key: "c", label: "C" }, - { key: "d", label: "D" }, - { key: "e", label: "E" }, - ], - paired: "dropdown", - }; - dropdownSetting = { - key: "dropdown", - label: "Dropdown", - default: "b", - options: [ - { key: "a", label: "A" }, - { key: "b", label: "B" }, - { key: "c", label: "C" }, - { key: "d", label: "D" }, - { key: "e", label: "E" }, - ], - type: "select", - }; - wrapper = mount( - - ); - }); - const menuOptions = () => { - return inputListSetting.options.map((o) => ( -