@@ -2,7 +2,6 @@ import React from 'react';
22import { expect } from 'chai' ;
33import sinon from 'sinon' ;
44import {
5- fireEvent ,
65 render ,
76 screen ,
87 cleanup ,
@@ -128,7 +127,7 @@ describe('CrudToolbar Component', function () {
128127 } ) ;
129128
130129 expect ( getPageSpy . called ) . to . be . false ;
131- fireEvent . click ( screen . getByTestId ( 'docs-toolbar-next-page-btn' ) ) ;
130+ userEvent . click ( screen . getByTestId ( 'docs-toolbar-next-page-btn' ) ) ;
132131
133132 expect ( getPageSpy . calledOnce ) . to . be . true ;
134133 expect ( getPageSpy . firstCall . args [ 0 ] ) . to . equal ( 1 ) ;
@@ -141,7 +140,7 @@ describe('CrudToolbar Component', function () {
141140 } ) ;
142141
143142 expect ( getPageSpy . called ) . to . be . false ;
144- fireEvent . click ( screen . getByTestId ( 'docs-toolbar-prev-page-btn' ) ) ;
143+ userEvent . click ( screen . getByTestId ( 'docs-toolbar-prev-page-btn' ) ) ;
145144
146145 expect ( screen . getByTestId ( 'docs-toolbar-prev-page-btn' ) ) . to . have . attribute (
147146 'aria-disabled' ,
@@ -164,7 +163,7 @@ describe('CrudToolbar Component', function () {
164163 end : 50 ,
165164 } ) ;
166165 expect ( getPageSpy . called ) . to . be . false ;
167- fireEvent . click ( screen . getByTestId ( 'docs-toolbar-next-page-btn' ) ) ;
166+ userEvent . click ( screen . getByTestId ( 'docs-toolbar-next-page-btn' ) ) ;
168167
169168 expect (
170169 screen . getByTestId ( 'docs-toolbar-next-page-btn' )
@@ -184,7 +183,7 @@ describe('CrudToolbar Component', function () {
184183 end : 25 ,
185184 } ) ;
186185 expect ( getPageSpy . called ) . to . be . false ;
187- fireEvent . click ( screen . getByTestId ( 'docs-toolbar-next-page-btn' ) ) ;
186+ userEvent . click ( screen . getByTestId ( 'docs-toolbar-next-page-btn' ) ) ;
188187
189188 expect (
190189 screen . getByTestId ( 'docs-toolbar-next-page-btn' )
@@ -209,7 +208,7 @@ describe('CrudToolbar Component', function () {
209208 ) ;
210209
211210 expect ( getPageSpy . called ) . to . be . false ;
212- fireEvent . click ( screen . getByTestId ( 'docs-toolbar-prev-page-btn' ) ) ;
211+ userEvent . click ( screen . getByTestId ( 'docs-toolbar-prev-page-btn' ) ) ;
213212
214213 expect ( getPageSpy . calledOnce ) . to . be . true ;
215214 expect ( getPageSpy . firstCall . args [ 0 ] ) . to . equal ( 0 ) ;
@@ -226,7 +225,7 @@ describe('CrudToolbar Component', function () {
226225 } ) ;
227226
228227 expect ( getPageSpy . called ) . to . be . false ;
229- fireEvent . click ( screen . getByTestId ( 'docs-toolbar-next-page-btn' ) ) ;
228+ userEvent . click ( screen . getByTestId ( 'docs-toolbar-next-page-btn' ) ) ;
230229
231230 expect ( screen . getByTestId ( 'docs-toolbar-next-page-btn' ) ) . to . have . attribute (
232231 'aria-disabled' ,
@@ -248,7 +247,7 @@ describe('CrudToolbar Component', function () {
248247 expect ( nextButton ) . to . have . attribute ( 'aria-disabled' , 'false' ) ;
249248
250249 expect ( getPageSpy . called ) . to . be . false ;
251- fireEvent . click ( nextButton ) ;
250+ userEvent . click ( nextButton ) ;
252251
253252 expect ( getPageSpy . calledOnce ) . to . be . true ;
254253 expect ( getPageSpy . firstCall . args [ 0 ] ) . to . equal ( 3 ) ;
@@ -295,8 +294,8 @@ describe('CrudToolbar Component', function () {
295294 } ) ;
296295
297296 expect ( exportSpy . called ) . to . be . false ;
298- fireEvent . click ( screen . getByText ( 'Export Data' ) ) ;
299- fireEvent . click ( screen . getByText ( 'Export the full collection' ) ) ;
297+ userEvent . click ( screen . getByText ( 'Export Data' ) ) ;
298+ userEvent . click ( screen . getByText ( 'Export the full collection' ) ) ;
300299
301300 expect ( exportSpy . calledOnce ) . to . be . true ;
302301 expect ( exportSpy . firstCall . args [ 0 ] ) . to . be . true ;
@@ -527,4 +526,262 @@ describe('CrudToolbar Component', function () {
527526 expect ( stub ) . to . be . calledWithExactly ( 75 ) ;
528527 } ) ;
529528 } ) ;
529+
530+ describe ( 'context menu' , function ( ) {
531+ beforeEach ( async function ( ) {
532+ await preferences . savePreferences ( { enableImportExport : true } ) ;
533+ } ) ;
534+
535+ it ( 'should open context menu on right click' , function ( ) {
536+ renderCrudToolbar ( ) ;
537+
538+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
539+ userEvent . click ( toolbar ! , { button : 2 } ) ;
540+
541+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
542+ expect ( within ( contextMenu ) . getByText ( 'Expand all documents' ) ) . to . be
543+ . visible ;
544+ expect ( within ( contextMenu ) . getByText ( 'Refresh' ) ) . to . be . visible ;
545+ } ) ;
546+
547+ it ( 'should call onExpandAllClicked when "Expand all documents" is clicked' , function ( ) {
548+ const onExpandAllClicked = sinon . spy ( ) ;
549+ renderCrudToolbar ( { onExpandAllClicked } ) ;
550+
551+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
552+ userEvent . click ( toolbar ! , { button : 2 } ) ;
553+
554+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
555+ const expandMenuItem = within ( contextMenu ) . getByText (
556+ 'Expand all documents'
557+ ) ;
558+ userEvent . click ( expandMenuItem ) ;
559+
560+ expect ( onExpandAllClicked ) . to . have . been . calledOnce ;
561+ } ) ;
562+
563+ it ( 'should call onCollapseAllClicked when "Collapse all documents" is clicked' , function ( ) {
564+ const onCollapseAllClicked = sinon . spy ( ) ;
565+ renderCrudToolbar ( { onCollapseAllClicked } ) ;
566+
567+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
568+ userEvent . click ( toolbar ! , { button : 2 } ) ;
569+
570+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
571+ const collapseMenuItem = within ( contextMenu ) . getByText (
572+ 'Collapse all documents'
573+ ) ;
574+ userEvent . click ( collapseMenuItem ) ;
575+
576+ expect ( onCollapseAllClicked ) . to . have . been . called ;
577+ } ) ;
578+
579+ it ( 'should call insertDataHandler with "import-file" when "Import JSON or CSV file" is clicked' , function ( ) {
580+ const insertDataHandler = sinon . spy ( ) ;
581+ renderCrudToolbar ( { insertDataHandler } ) ;
582+
583+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
584+ userEvent . click ( toolbar ! , { button : 2 } ) ;
585+
586+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
587+ const importMenuItem = within ( contextMenu ) . getByText (
588+ 'Import JSON or CSV file'
589+ ) ;
590+ userEvent . click ( importMenuItem ) ;
591+
592+ expect ( insertDataHandler ) . to . have . been . calledOnceWithExactly (
593+ 'import-file'
594+ ) ;
595+ } ) ;
596+
597+ it ( 'should call insertDataHandler with "insert-document" when "Insert document..." is clicked' , function ( ) {
598+ const insertDataHandler = sinon . spy ( ) ;
599+ renderCrudToolbar ( { insertDataHandler } ) ;
600+
601+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
602+ userEvent . click ( toolbar ! , { button : 2 } ) ;
603+
604+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
605+ const insertMenuItem =
606+ within ( contextMenu ) . getByText ( 'Insert document...' ) ;
607+ userEvent . click ( insertMenuItem ) ;
608+
609+ expect ( insertDataHandler ) . to . have . been . calledOnceWithExactly (
610+ 'insert-document'
611+ ) ;
612+ } ) ;
613+
614+ it ( 'should call openExportFileDialog with false when "Export query results..." is clicked' , function ( ) {
615+ const openExportFileDialog = sinon . spy ( ) ;
616+ renderCrudToolbar ( { openExportFileDialog } ) ;
617+
618+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
619+ userEvent . click ( toolbar ! , { button : 2 } ) ;
620+
621+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
622+ const exportQueryMenuItem = within ( contextMenu ) . getByText (
623+ 'Export query results...'
624+ ) ;
625+ userEvent . click ( exportQueryMenuItem ) ;
626+
627+ expect ( openExportFileDialog ) . to . have . been . calledOnceWithExactly ( false ) ;
628+ } ) ;
629+
630+ it ( 'should call openExportFileDialog with true when "Export full collection..." is clicked' , function ( ) {
631+ const openExportFileDialog = sinon . spy ( ) ;
632+ renderCrudToolbar ( { openExportFileDialog } ) ;
633+
634+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
635+ userEvent . click ( toolbar ! , { button : 2 } ) ;
636+
637+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
638+ const exportCollectionMenuItem = within ( contextMenu ) . getByText (
639+ 'Export full collection...'
640+ ) ;
641+ userEvent . click ( exportCollectionMenuItem ) ;
642+
643+ expect ( openExportFileDialog ) . to . have . been . calledOnceWithExactly ( true ) ;
644+ } ) ;
645+
646+ it ( 'should call onUpdateButtonClicked when "Bulk update" is clicked' , function ( ) {
647+ const onUpdateButtonClicked = sinon . spy ( ) ;
648+ renderCrudToolbar ( { onUpdateButtonClicked } ) ;
649+
650+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
651+ userEvent . click ( toolbar ! , { button : 2 } ) ;
652+
653+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
654+ const updateMenuItem = within ( contextMenu ) . getByText ( 'Bulk update' ) ;
655+ userEvent . click ( updateMenuItem ) ;
656+
657+ expect ( onUpdateButtonClicked ) . to . have . been . calledOnce ;
658+ } ) ;
659+
660+ it ( 'should call onDeleteButtonClicked when "Bulk delete" is clicked' , function ( ) {
661+ const onDeleteButtonClicked = sinon . spy ( ) ;
662+ renderCrudToolbar ( { onDeleteButtonClicked } ) ;
663+
664+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
665+ userEvent . click ( toolbar ! , { button : 2 } ) ;
666+
667+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
668+ const deleteMenuItem = within ( contextMenu ) . getByText ( 'Bulk delete' ) ;
669+ userEvent . click ( deleteMenuItem ) ;
670+
671+ expect ( onDeleteButtonClicked ) . to . have . been . calledOnce ;
672+ } ) ;
673+
674+ it ( 'should call refreshDocuments when "Refresh" is clicked' , function ( ) {
675+ const refreshDocuments = sinon . spy ( ) ;
676+ renderCrudToolbar ( { refreshDocuments } ) ;
677+
678+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
679+ userEvent . click ( toolbar ! , { button : 2 } ) ;
680+
681+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
682+ const refreshMenuItem = within ( contextMenu ) . getByText ( 'Refresh' ) ;
683+ userEvent . click ( refreshMenuItem ) ;
684+
685+ expect ( refreshDocuments ) . to . have . been . calledOnce ;
686+ } ) ;
687+
688+ describe ( 'conditional menu items' , function ( ) {
689+ it ( 'should not show import/export items when enableImportExport is false' , async function ( ) {
690+ await preferences . savePreferences ( { enableImportExport : false } ) ;
691+ renderCrudToolbar ( ) ;
692+
693+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
694+ userEvent . click ( toolbar ! , { button : 2 } ) ;
695+
696+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
697+ expect ( within ( contextMenu ) . queryByText ( 'Import JSON or CSV file' ) ) . to
698+ . not . exist ;
699+ expect ( within ( contextMenu ) . queryByText ( 'Export query results...' ) ) . to
700+ . not . exist ;
701+ expect ( within ( contextMenu ) . queryByText ( 'Export full collection...' ) ) . to
702+ . not . exist ;
703+ } ) ;
704+
705+ it ( 'should not show insert document item when readonly is true' , function ( ) {
706+ renderCrudToolbar ( { readonly : true } ) ;
707+
708+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
709+ userEvent . click ( toolbar ! , { button : 2 } ) ;
710+
711+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
712+ expect ( within ( contextMenu ) . queryByText ( 'Insert document...' ) ) . to . not
713+ . exist ;
714+ } ) ;
715+
716+ it ( 'should not show bulk operations when readonly is true' , function ( ) {
717+ renderCrudToolbar ( { readonly : true } ) ;
718+
719+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
720+ userEvent . click ( toolbar ! , { button : 2 } ) ;
721+
722+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
723+ expect ( within ( contextMenu ) . queryByText ( 'Bulk update' ) ) . to . not . exist ;
724+ expect ( within ( contextMenu ) . queryByText ( 'Bulk delete' ) ) . to . not . exist ;
725+ } ) ;
726+
727+ it ( 'should not show bulk operations when isWritable is false' , function ( ) {
728+ renderCrudToolbar ( { isWritable : false } ) ;
729+
730+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
731+ userEvent . click ( toolbar ! , { button : 2 } ) ;
732+
733+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
734+ expect ( within ( contextMenu ) . queryByText ( 'Bulk update' ) ) . to . not . exist ;
735+ expect ( within ( contextMenu ) . queryByText ( 'Bulk delete' ) ) . to . not . exist ;
736+ } ) ;
737+
738+ it ( 'should not show bulk operations when query has skip' , function ( ) {
739+ renderCrudToolbar ( { querySkip : 10 } ) ;
740+
741+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
742+ userEvent . click ( toolbar ! , { button : 2 } ) ;
743+
744+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
745+ expect ( within ( contextMenu ) . queryByText ( 'Bulk update' ) ) . to . not . exist ;
746+ } ) ;
747+
748+ it ( 'should not show bulk operations when query has limit' , function ( ) {
749+ renderCrudToolbar ( { queryLimit : 10 } ) ;
750+
751+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
752+ userEvent . click ( toolbar ! , { button : 2 } ) ;
753+
754+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
755+ expect ( within ( contextMenu ) . queryByText ( 'Bulk update' ) ) . to . not . exist ;
756+ expect ( within ( contextMenu ) . queryByText ( 'Bulk delete' ) ) . to . not . exist ;
757+ } ) ;
758+
759+ it ( 'should show all applicable items when conditions are met' , function ( ) {
760+ renderCrudToolbar ( {
761+ readonly : false ,
762+ isWritable : true ,
763+ querySkip : 0 ,
764+ queryLimit : 0 ,
765+ } ) ;
766+
767+ const toolbar = screen . getByTestId ( 'query-bar' ) . closest ( 'div' ) ;
768+ userEvent . click ( toolbar ! , { button : 2 } ) ;
769+
770+ const contextMenu = screen . getByTestId ( 'context-menu' ) ;
771+ expect ( within ( contextMenu ) . getByText ( 'Expand all documents' ) ) . to . be
772+ . visible ;
773+ expect ( within ( contextMenu ) . getByText ( 'Import JSON or CSV file' ) ) . to . be
774+ . visible ;
775+ expect ( within ( contextMenu ) . getByText ( 'Insert document...' ) ) . to . be
776+ . visible ;
777+ expect ( within ( contextMenu ) . getByText ( 'Export query results...' ) ) . to . be
778+ . visible ;
779+ expect ( within ( contextMenu ) . getByText ( 'Export full collection...' ) ) . to . be
780+ . visible ;
781+ expect ( within ( contextMenu ) . getByText ( 'Bulk update' ) ) . to . be . visible ;
782+ expect ( within ( contextMenu ) . getByText ( 'Bulk delete' ) ) . to . be . visible ;
783+ expect ( within ( contextMenu ) . getByText ( 'Refresh' ) ) . to . be . visible ;
784+ } ) ;
785+ } ) ;
786+ } ) ;
530787} ) ;
0 commit comments