@@ -2,10 +2,8 @@ import React from 'react';
22import { expect } from 'chai' ;
33import sinon from 'sinon' ;
44import {
5- fireEvent ,
65 render ,
76 screen ,
8- cleanup ,
97 within ,
108 userEvent ,
119} from '@mongodb-js/testing-library-compass' ;
@@ -71,7 +69,7 @@ describe('CrudToolbar Component', function () {
7169 onResetClicked = { noop }
7270 onUpdateButtonClicked = { noop }
7371 onDeleteButtonClicked = { noop }
74- onExpandAllClicked = { noop }
72+ onExpandAllClicked = { props ?. onExpandAllClicked || noop }
7573 onCollapseAllClicked = { noop }
7674 openExportFileDialog = { noop }
7775 outdated = { false }
@@ -91,10 +89,6 @@ describe('CrudToolbar Component', function () {
9189 ) ;
9290 }
9391
94- afterEach ( function ( ) {
95- cleanup ( ) ;
96- } ) ;
97-
9892 beforeEach ( async function ( ) {
9993 preferences = await createSandboxFromDefaultPreferences ( ) ;
10094 } ) ;
@@ -128,7 +122,7 @@ describe('CrudToolbar Component', function () {
128122 } ) ;
129123
130124 expect ( getPageSpy . called ) . to . be . false ;
131- fireEvent . click ( screen . getByTestId ( 'docs-toolbar-next-page-btn' ) ) ;
125+ userEvent . click ( screen . getByTestId ( 'docs-toolbar-next-page-btn' ) ) ;
132126
133127 expect ( getPageSpy . calledOnce ) . to . be . true ;
134128 expect ( getPageSpy . firstCall . args [ 0 ] ) . to . equal ( 1 ) ;
@@ -141,7 +135,7 @@ describe('CrudToolbar Component', function () {
141135 } ) ;
142136
143137 expect ( getPageSpy . called ) . to . be . false ;
144- fireEvent . click ( screen . getByTestId ( 'docs-toolbar-prev-page-btn' ) ) ;
138+ userEvent . click ( screen . getByTestId ( 'docs-toolbar-prev-page-btn' ) ) ;
145139
146140 expect ( screen . getByTestId ( 'docs-toolbar-prev-page-btn' ) ) . to . have . attribute (
147141 'aria-disabled' ,
@@ -164,7 +158,7 @@ describe('CrudToolbar Component', function () {
164158 end : 50 ,
165159 } ) ;
166160 expect ( getPageSpy . called ) . to . be . false ;
167- fireEvent . click ( screen . getByTestId ( 'docs-toolbar-next-page-btn' ) ) ;
161+ userEvent . click ( screen . getByTestId ( 'docs-toolbar-next-page-btn' ) ) ;
168162
169163 expect (
170164 screen . getByTestId ( 'docs-toolbar-next-page-btn' )
@@ -184,7 +178,7 @@ describe('CrudToolbar Component', function () {
184178 end : 25 ,
185179 } ) ;
186180 expect ( getPageSpy . called ) . to . be . false ;
187- fireEvent . click ( screen . getByTestId ( 'docs-toolbar-next-page-btn' ) ) ;
181+ userEvent . click ( screen . getByTestId ( 'docs-toolbar-next-page-btn' ) ) ;
188182
189183 expect (
190184 screen . getByTestId ( 'docs-toolbar-next-page-btn' )
@@ -209,7 +203,7 @@ describe('CrudToolbar Component', function () {
209203 ) ;
210204
211205 expect ( getPageSpy . called ) . to . be . false ;
212- fireEvent . click ( screen . getByTestId ( 'docs-toolbar-prev-page-btn' ) ) ;
206+ userEvent . click ( screen . getByTestId ( 'docs-toolbar-prev-page-btn' ) ) ;
213207
214208 expect ( getPageSpy . calledOnce ) . to . be . true ;
215209 expect ( getPageSpy . firstCall . args [ 0 ] ) . to . equal ( 0 ) ;
@@ -226,7 +220,7 @@ describe('CrudToolbar Component', function () {
226220 } ) ;
227221
228222 expect ( getPageSpy . called ) . to . be . false ;
229- fireEvent . click ( screen . getByTestId ( 'docs-toolbar-next-page-btn' ) ) ;
223+ userEvent . click ( screen . getByTestId ( 'docs-toolbar-next-page-btn' ) ) ;
230224
231225 expect ( screen . getByTestId ( 'docs-toolbar-next-page-btn' ) ) . to . have . attribute (
232226 'aria-disabled' ,
@@ -248,7 +242,7 @@ describe('CrudToolbar Component', function () {
248242 expect ( nextButton ) . to . have . attribute ( 'aria-disabled' , 'false' ) ;
249243
250244 expect ( getPageSpy . called ) . to . be . false ;
251- fireEvent . click ( nextButton ) ;
245+ userEvent . click ( nextButton ) ;
252246
253247 expect ( getPageSpy . calledOnce ) . to . be . true ;
254248 expect ( getPageSpy . firstCall . args [ 0 ] ) . to . equal ( 3 ) ;
@@ -295,8 +289,8 @@ describe('CrudToolbar Component', function () {
295289 } ) ;
296290
297291 expect ( exportSpy . called ) . to . be . false ;
298- fireEvent . click ( screen . getByText ( 'Export Data' ) ) ;
299- fireEvent . click ( screen . getByText ( 'Export the full collection' ) ) ;
292+ userEvent . click ( screen . getByText ( 'Export Data' ) ) ;
293+ userEvent . click ( screen . getByText ( 'Export the full collection' ) ) ;
300294
301295 expect ( exportSpy . calledOnce ) . to . be . true ;
302296 expect ( exportSpy . firstCall . args [ 0 ] ) . to . be . true ;
@@ -527,4 +521,262 @@ describe('CrudToolbar Component', function () {
527521 expect ( stub ) . to . be . calledWithExactly ( 75 ) ;
528522 } ) ;
529523 } ) ;
524+
525+ describe ( 'context menu' , function ( ) {
526+ beforeEach ( async function ( ) {
527+ await preferences . savePreferences ( { enableImportExport : true } ) ;
528+ } ) ;
529+
530+ it ( 'should open context menu on right click' , async function ( ) {
531+ renderCrudToolbar ( ) ;
532+
533+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
534+ await userEvent . pointer ( { target : toolbar ! , keys : '[MouseRight]' } ) ;
535+
536+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
537+ expect ( within ( contextMenu ) . getByText ( 'Expand all documents' ) ) . to . be
538+ . visible ;
539+ expect ( within ( contextMenu ) . getByText ( 'Refresh' ) ) . to . be . visible ;
540+ } ) ;
541+
542+ it ( 'should call onExpandAllClicked when "Expand all documents" is clicked' , async function ( ) {
543+ const onExpandAllClicked = sinon . spy ( ) ;
544+ renderCrudToolbar ( { onExpandAllClicked } ) ;
545+
546+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
547+ userEvent . click ( toolbar ! , { button : 2 } ) ;
548+
549+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
550+ const expandMenuItem = within ( contextMenu ) . getByText (
551+ 'Expand all documents'
552+ ) ;
553+ userEvent . click ( expandMenuItem ) ;
554+
555+ expect ( onExpandAllClicked ) . to . have . been . calledOnce ;
556+ } ) ;
557+
558+ it ( 'should call onCollapseAllClicked when "Collapse all documents" is clicked' , function ( ) {
559+ const onCollapseAllClicked = sinon . spy ( ) ;
560+ renderCrudToolbar ( { onCollapseAllClicked } ) ;
561+
562+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
563+ userEvent . click ( toolbar ! , { button : 2 } ) ;
564+
565+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
566+ const collapseMenuItem = within ( contextMenu ) . getByText (
567+ 'Collapse all documents'
568+ ) ;
569+ userEvent . click ( collapseMenuItem ) ;
570+
571+ expect ( onCollapseAllClicked ) . to . have . been . calledOnce ;
572+ } ) ;
573+
574+ it ( 'should call insertDataHandler with "import-file" when "Import JSON or CSV file" is clicked' , function ( ) {
575+ const insertDataHandler = sinon . spy ( ) ;
576+ renderCrudToolbar ( { insertDataHandler } ) ;
577+
578+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
579+ userEvent . click ( toolbar ! , { button : 2 } ) ;
580+
581+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
582+ const importMenuItem = within ( contextMenu ) . getByText (
583+ 'Import JSON or CSV file'
584+ ) ;
585+ userEvent . click ( importMenuItem ) ;
586+
587+ expect ( insertDataHandler ) . to . have . been . calledOnceWithExactly (
588+ 'import-file'
589+ ) ;
590+ } ) ;
591+
592+ it ( 'should call insertDataHandler with "insert-document" when "Insert document..." is clicked' , function ( ) {
593+ const insertDataHandler = sinon . spy ( ) ;
594+ renderCrudToolbar ( { insertDataHandler } ) ;
595+
596+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
597+ userEvent . click ( toolbar ! , { button : 2 } ) ;
598+
599+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
600+ const insertMenuItem =
601+ within ( contextMenu ) . getByText ( 'Insert document...' ) ;
602+ userEvent . click ( insertMenuItem ) ;
603+
604+ expect ( insertDataHandler ) . to . have . been . calledOnceWithExactly (
605+ 'insert-document'
606+ ) ;
607+ } ) ;
608+
609+ it ( 'should call openExportFileDialog with false when "Export query results..." is clicked' , function ( ) {
610+ const openExportFileDialog = sinon . spy ( ) ;
611+ renderCrudToolbar ( { openExportFileDialog } ) ;
612+
613+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
614+ userEvent . click ( toolbar ! , { button : 2 } ) ;
615+
616+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
617+ const exportQueryMenuItem = within ( contextMenu ) . getByText (
618+ 'Export query results...'
619+ ) ;
620+ userEvent . click ( exportQueryMenuItem ) ;
621+
622+ expect ( openExportFileDialog ) . to . have . been . calledOnceWithExactly ( false ) ;
623+ } ) ;
624+
625+ it ( 'should call openExportFileDialog with true when "Export full collection..." is clicked' , function ( ) {
626+ const openExportFileDialog = sinon . spy ( ) ;
627+ renderCrudToolbar ( { openExportFileDialog } ) ;
628+
629+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
630+ userEvent . click ( toolbar ! , { button : 2 } ) ;
631+
632+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
633+ const exportCollectionMenuItem = within ( contextMenu ) . getByText (
634+ 'Export full collection...'
635+ ) ;
636+ userEvent . click ( exportCollectionMenuItem ) ;
637+
638+ expect ( openExportFileDialog ) . to . have . been . calledOnceWithExactly ( true ) ;
639+ } ) ;
640+
641+ it ( 'should call onUpdateButtonClicked when "Bulk update" is clicked' , function ( ) {
642+ const onUpdateButtonClicked = sinon . spy ( ) ;
643+ renderCrudToolbar ( { onUpdateButtonClicked } ) ;
644+
645+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
646+ userEvent . click ( toolbar ! , { button : 2 } ) ;
647+
648+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
649+ const updateMenuItem = within ( contextMenu ) . getByText ( 'Bulk update' ) ;
650+ userEvent . click ( updateMenuItem ) ;
651+
652+ expect ( onUpdateButtonClicked ) . to . have . been . calledOnce ;
653+ } ) ;
654+
655+ it ( 'should call onDeleteButtonClicked when "Bulk delete" is clicked' , function ( ) {
656+ const onDeleteButtonClicked = sinon . spy ( ) ;
657+ renderCrudToolbar ( { onDeleteButtonClicked } ) ;
658+
659+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
660+ userEvent . click ( toolbar ! , { button : 2 } ) ;
661+
662+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
663+ const deleteMenuItem = within ( contextMenu ) . getByText ( 'Bulk delete' ) ;
664+ userEvent . click ( deleteMenuItem ) ;
665+
666+ expect ( onDeleteButtonClicked ) . to . have . been . calledOnce ;
667+ } ) ;
668+
669+ it ( 'should call refreshDocuments when "Refresh" is clicked' , function ( ) {
670+ const refreshDocuments = sinon . spy ( ) ;
671+ renderCrudToolbar ( { refreshDocuments } ) ;
672+
673+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
674+ userEvent . click ( toolbar ! , { button : 2 } ) ;
675+
676+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
677+ const refreshMenuItem = within ( contextMenu ) . getByText ( 'Refresh' ) ;
678+ userEvent . click ( refreshMenuItem ) ;
679+
680+ expect ( refreshDocuments ) . to . have . been . calledOnce ;
681+ } ) ;
682+
683+ describe ( 'conditional menu items' , function ( ) {
684+ it ( 'should not show import/export items when enableImportExport is false' , async function ( ) {
685+ await preferences . savePreferences ( { enableImportExport : false } ) ;
686+ renderCrudToolbar ( ) ;
687+
688+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
689+ userEvent . click ( toolbar ! , { button : 2 } ) ;
690+
691+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
692+ expect ( within ( contextMenu ) . queryByText ( 'Import JSON or CSV file' ) ) . to
693+ . not . exist ;
694+ expect ( within ( contextMenu ) . queryByText ( 'Export query results...' ) ) . to
695+ . not . exist ;
696+ expect ( within ( contextMenu ) . queryByText ( 'Export full collection...' ) ) . to
697+ . not . exist ;
698+ } ) ;
699+
700+ it ( 'should not show insert document item when readonly is true' , function ( ) {
701+ renderCrudToolbar ( { readonly : true } ) ;
702+
703+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
704+ userEvent . click ( toolbar ! , { button : 2 } ) ;
705+
706+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
707+ expect ( within ( contextMenu ) . queryByText ( 'Insert document...' ) ) . to . not
708+ . exist ;
709+ } ) ;
710+
711+ it ( 'should not show bulk operations when readonly is true' , function ( ) {
712+ renderCrudToolbar ( { readonly : true } ) ;
713+
714+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
715+ userEvent . click ( toolbar ! , { button : 2 } ) ;
716+
717+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
718+ expect ( within ( contextMenu ) . queryByText ( 'Bulk update' ) ) . to . not . exist ;
719+ expect ( within ( contextMenu ) . queryByText ( 'Bulk delete' ) ) . to . not . exist ;
720+ } ) ;
721+
722+ it ( 'should not show bulk operations when isWritable is false' , function ( ) {
723+ renderCrudToolbar ( { isWritable : false } ) ;
724+
725+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
726+ userEvent . click ( toolbar ! , { button : 2 } ) ;
727+
728+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
729+ expect ( within ( contextMenu ) . queryByText ( 'Bulk update' ) ) . to . not . exist ;
730+ expect ( within ( contextMenu ) . queryByText ( 'Bulk delete' ) ) . to . not . exist ;
731+ } ) ;
732+
733+ it ( 'should not show bulk operations when query has skip' , function ( ) {
734+ renderCrudToolbar ( { querySkip : 10 } ) ;
735+
736+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
737+ userEvent . click ( toolbar ! , { button : 2 } ) ;
738+
739+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
740+ expect ( within ( contextMenu ) . queryByText ( 'Bulk update' ) ) . to . not . exist ;
741+ } ) ;
742+
743+ it ( 'should not show bulk operations when query has limit' , function ( ) {
744+ renderCrudToolbar ( { queryLimit : 10 } ) ;
745+
746+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
747+ userEvent . click ( toolbar ! , { button : 2 } ) ;
748+
749+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
750+ expect ( within ( contextMenu ) . queryByText ( 'Bulk update' ) ) . to . not . exist ;
751+ expect ( within ( contextMenu ) . queryByText ( 'Bulk delete' ) ) . to . not . exist ;
752+ } ) ;
753+
754+ it ( 'should show all applicable items when conditions are met' , function ( ) {
755+ renderCrudToolbar ( {
756+ readonly : false ,
757+ isWritable : true ,
758+ querySkip : 0 ,
759+ queryLimit : 0 ,
760+ } ) ;
761+
762+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
763+ userEvent . click ( toolbar ! , { button : 2 } ) ;
764+
765+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
766+ expect ( within ( contextMenu ) . getByText ( 'Expand all documents' ) ) . to . be
767+ . visible ;
768+ expect ( within ( contextMenu ) . getByText ( 'Import JSON or CSV file' ) ) . to . be
769+ . visible ;
770+ expect ( within ( contextMenu ) . getByText ( 'Insert document...' ) ) . to . be
771+ . visible ;
772+ expect ( within ( contextMenu ) . getByText ( 'Export query results...' ) ) . to . be
773+ . visible ;
774+ expect ( within ( contextMenu ) . getByText ( 'Export full collection...' ) ) . to . be
775+ . visible ;
776+ expect ( within ( contextMenu ) . getByText ( 'Bulk update' ) ) . to . be . visible ;
777+ expect ( within ( contextMenu ) . getByText ( 'Bulk delete' ) ) . to . be . visible ;
778+ expect ( within ( contextMenu ) . getByText ( 'Refresh' ) ) . to . be . visible ;
779+ } ) ;
780+ } ) ;
781+ } ) ;
530782} ) ;
0 commit comments