mirror of
				https://github.com/gristlabs/grist-core.git
				synced 2025-06-13 20:53:59 +00:00 
			
		
		
		
	(core) Fix and move filter tests to grist-core
Summary: A few tests that hadn't been ported to grist-core yet began failing after a change in behavior with the column filter menu. Test Plan: Existing tests. Reviewers: jarek Reviewed By: jarek Differential Revision: https://phab.getgrist.com/D4260
This commit is contained in:
		
							parent
							
								
									76a43129f1
								
							
						
					
					
						commit
						15590950e6
					
				
							
								
								
									
										621
									
								
								test/nbrowser/ColumnFilterMenu.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										621
									
								
								test/nbrowser/ColumnFilterMenu.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,621 @@ | ||||
| import { UserAPI } from 'app/common/UserAPI'; | ||||
| import { addToRepl, assert, driver, Key } from 'mocha-webdriver'; | ||||
| import * as gu from 'test/nbrowser/gristUtils'; | ||||
| import { setupTestSuite } from 'test/nbrowser/testUtils'; | ||||
| 
 | ||||
| const limitShown = 500; | ||||
| 
 | ||||
| // Sum all of the counts directly on the browser using `driver.executeScript(...)`. There could me
 | ||||
| // over 500 of them and using the classic driver.findAll(...) approach makes it too slow and causes
 | ||||
| // the test to crash (timeout).
 | ||||
| function getCount() { | ||||
|   return driver.executeScript(` | ||||
|   return Array.from(document.querySelectorAll('.test-filter-menu-count'), e => e.innerText) | ||||
|     .map(s => s.split(',').join('')) | ||||
|     .map(Number) | ||||
|     .reduce((acc, v) => acc + v, 0); | ||||
| `);
 | ||||
| } | ||||
| 
 | ||||
| // find a filter value by name
 | ||||
| function findByName(regex: RegExp | string) { | ||||
|   return driver.findContent('.test-filter-menu-list label', regex); | ||||
| } | ||||
| 
 | ||||
| describe('ColumnFilterMenu', function() { | ||||
|   this.timeout(20000); | ||||
|   const cleanup = setupTestSuite(); | ||||
|   addToRepl('findByName', findByName); | ||||
|   let doc: any; | ||||
|   let api: UserAPI; | ||||
| 
 | ||||
|   it('should handle empty lists consistently', async function() { | ||||
|     // A formula returning an empty RecordSet in a RefList columns results in storing [] instead of null.
 | ||||
|     // This previously caused a bug where the empty list was 'flattened' and the cell not appearing in filters at all.
 | ||||
|     const session = await gu.session().teamSite.login(); | ||||
|     const api = session.createHomeApi(); | ||||
|     const docId = await session.tempNewDoc(cleanup, 'FilterEmptyLists', {load: false}); | ||||
| 
 | ||||
|     await api.applyUserActions(docId, [ | ||||
|       ['AddTable', 'Table2', [ | ||||
|         { | ||||
|           id: 'A', type: 'RefList:Table2', isFormula: true, | ||||
|           // This means that the first cell will contain [] while the second will contain null.
 | ||||
|           // The test asserts that both end up being treated the same.
 | ||||
|           formula: 'if $id == 1: return table.lookupRecords(B="foobar")' | ||||
|         }, | ||||
|         {id: 'B'}, | ||||
|       ]], | ||||
|       ['BulkAddRecord', 'Table2', [null, null], {B: [1, 2]}], | ||||
|     ]); | ||||
| 
 | ||||
|     await session.loadDoc(`/doc/${docId}/p/2`); | ||||
| 
 | ||||
|     await gu.rightClick(gu.getCell({rowNum: 1, col: 'A'})); | ||||
|     await driver.findContent('.grist-floating-menu li', 'Filter by this value').click(); | ||||
| 
 | ||||
|     assert.deepEqual( | ||||
|       await gu.getVisibleGridCells({cols: ['A', 'B'], rowNums: [1, 2, 3]}), | ||||
|       [ | ||||
|         '', '1', | ||||
|         '', '2', | ||||
|         '', '' | ||||
|       ] | ||||
|     ); | ||||
| 
 | ||||
|     await gu.openColumnMenu('A', 'Filter'); | ||||
| 
 | ||||
|     assert.deepEqual( | ||||
|       await driver.findAll('.test-filter-menu-list .test-filter-menu-count', (e) => e.getText()), | ||||
|       ['2'], | ||||
|     ); | ||||
|   }); | ||||
| 
 | ||||
|   it('should show only first 500', async function() { | ||||
|     const session = await gu.session().teamSite.login(); | ||||
|     await session.tempDoc(cleanup, 'World.grist'); | ||||
| 
 | ||||
|     // check row count is > 4000
 | ||||
|     const total = await gu.getGridRowCount() - 1; | ||||
|     assert.equal(total, 4079); | ||||
| 
 | ||||
|     // scroll back to top
 | ||||
|     await gu.sendKeys(Key.chord(await gu.modKey(), Key.UP)); | ||||
| 
 | ||||
|     // open filter menu for first column
 | ||||
|     await gu.openColumnMenu('Name', 'Filter'); | ||||
| 
 | ||||
|     // check ther are 500 entry shown
 | ||||
|     assert.lengthOf(await driver.findAll('.test-filter-menu-list label'), limitShown); | ||||
| 
 | ||||
|     // check `Other` summary is present
 | ||||
|     assert.deepEqual( | ||||
|       await driver.findAll('.test-filter-menu-summary', (e) => e.find('label').getText()), | ||||
|       ['Other Values (3,501)', 'Future Values'] | ||||
|     ); | ||||
| 
 | ||||
|     // check counts add up
 | ||||
|     assert.equal(await getCount(), total); | ||||
| 
 | ||||
|     // type 'A' to search
 | ||||
|     await gu.sendKeys('A'); | ||||
| 
 | ||||
|     // check summary has `Other matching` and Other Non-matching`
 | ||||
|     assert.deepEqual( | ||||
|       await driver.findAll('.test-filter-menu-summary', (e) => e.find('label').getText()), | ||||
|       ['Other Matching (2,493)', 'Other Non-Matching (1,008)'] | ||||
|     ); | ||||
| 
 | ||||
|     // check count adds up
 | ||||
|     assert.equal(await getCount(), total); | ||||
| 
 | ||||
|     // clear search input
 | ||||
|     await gu.sendKeys(Key.BACK_SPACE); | ||||
| 
 | ||||
|     // Click All Except / Other Matching / Other NOn-Matching
 | ||||
|     await driver.findContent('.test-filter-menu-bulk-action', /None/).click(); | ||||
| 
 | ||||
|     // click Aba and Abadan
 | ||||
|     await driver.findContent('.test-filter-menu-list label', /Aba/).click(); | ||||
|     await driver.findContent('.test-filter-menu-list label', /Abadan/).click(); | ||||
| 
 | ||||
|     // Apply filter
 | ||||
|     await driver.find('.test-filter-menu-apply-btn').click(); | ||||
| 
 | ||||
|     // check grid contains aba and abadan
 | ||||
|     assert.deepEqual( | ||||
|       await gu.getVisibleGridCells({cols: ['Name'], rowNums: [1, 2, 3]}), | ||||
|       [ | ||||
|         'Aba', | ||||
|         'Abadan', | ||||
|         '' | ||||
|       ] | ||||
|     ); | ||||
| 
 | ||||
|   }); | ||||
| 
 | ||||
|   it('should uncheck \'Other Values\' checkbox when user clicks \'None\'', async () => { | ||||
|     // open the Name filter
 | ||||
|     await gu.openColumnMenu('Name', 'Filter'); | ||||
| 
 | ||||
|     // click None
 | ||||
|     await driver.findContent('.test-filter-menu-bulk-action', /None/).click(); | ||||
| 
 | ||||
|     // check Other values was propertly unchecked
 | ||||
|     assert.equal( | ||||
|       await driver.findContent('.test-filter-menu-summary', /Other Values/).find('input').matches(':checked'), | ||||
|       false | ||||
|     ); | ||||
| 
 | ||||
|     assert.equal( | ||||
|       await driver.findContent('.test-filter-menu-summary', /Future Values/).find('input').matches(':checked'), | ||||
|       false | ||||
|     ); | ||||
|   }); | ||||
| 
 | ||||
|   it('should take other filters into account', async () => { | ||||
| 
 | ||||
|     const session = await gu.session().teamSite.login(); | ||||
|     doc = await session.tempDoc(cleanup, 'SortFilterIconTest.grist'); | ||||
|     api = session.createHomeApi(); | ||||
| 
 | ||||
|     // check table content
 | ||||
|     assert.deepEqual( | ||||
|       await gu.getVisibleGridCells({cols: ['Name', 'Count'], rowNums: [1, 2, 3, 4, 5, 6]}), | ||||
|       [ 'Apples', '1', | ||||
|         'Oranges', '3', | ||||
|         'Bananas', '2', | ||||
|         'Grapes', '-1', | ||||
|         'Grapefruit', 'n/a', | ||||
|         'Clementines', '5' | ||||
|       ]); | ||||
| 
 | ||||
|     // add Name Filter
 | ||||
|     await gu.openColumnMenu('Name', 'Filter'); | ||||
| 
 | ||||
|     // Click Oranges
 | ||||
|     await findByName('Oranges').click(); | ||||
| 
 | ||||
|     // Click Apply
 | ||||
|     await driver.find('.test-filter-menu-apply-btn').click(); | ||||
| 
 | ||||
|     // add Count filters
 | ||||
|     await driver.find('.test-add-filter-btn').click(); | ||||
|     await driver.findContent('.grist-floating-menu li', /Count/).click(); | ||||
| 
 | ||||
|     // Check that there's only 5 values left ('3' is missing)
 | ||||
|     assert.deepEqual(await driver.findAll('.test-filter-menu-list label', (e) => e.getText()), | ||||
|                      ['n/a', '-1', '1', '2', '5']); | ||||
| 
 | ||||
|     // Check `Others` shows unique count
 | ||||
|     assert.equal(await driver.find('.test-filter-menu-summary').getText(), | ||||
|                  'Others (1)'); | ||||
| 
 | ||||
|     // Check `Others` is checked
 | ||||
|     assert.equal(await driver.find('.test-filter-menu-summary').find('input').matches(':checked'), true); | ||||
| 
 | ||||
|     // Click `Other`
 | ||||
|     await driver.find('.test-filter-menu-summary').find('input').click(); | ||||
| 
 | ||||
|     // Click '1'
 | ||||
|     await findByName(/^1/).click(); | ||||
| 
 | ||||
|     // Click Apply
 | ||||
|     await driver.find('.test-filter-menu-apply-btn').click(); | ||||
| 
 | ||||
|     // Open the Name menu filter
 | ||||
|     await driver.findContent('.test-filter-field', /Name/).click(); | ||||
| 
 | ||||
|     // Check there's only 4 values left
 | ||||
|     assert.deepEqual(await driver.findAll('.test-filter-menu-list label', (e) => e.getText()), | ||||
|                      ['Bananas', 'Clementines', 'Grapefruit', 'Grapes']); | ||||
| 
 | ||||
|     // check `Others` shows 2 unique values
 | ||||
|     assert.equal(await driver.find('.test-filter-menu-summary').getText(), | ||||
|                  'Others (2)'); | ||||
| 
 | ||||
|     // check `Others` is in indeterminate state
 | ||||
|     assert.equal(await driver.find('.test-filter-menu-summary').find('input').matches(':checked'), false); | ||||
|     assert.equal(await driver.find('.test-filter-menu-summary').find('input').matches(':indeterminate'), true); | ||||
| 
 | ||||
|     // Click `Others`
 | ||||
|     await driver.find('.test-filter-menu-summary').find('input').click(); | ||||
| 
 | ||||
|     // check `Others` is checked
 | ||||
|     assert.equal(await driver.find('.test-filter-menu-summary').find('input').matches(':checked'), true); | ||||
|     assert.equal(await driver.find('.test-filter-menu-summary').find('input').matches(':indeterminate'), false); | ||||
| 
 | ||||
|     // Click `Others`
 | ||||
|     await driver.find('.test-filter-menu-summary').find('input').click(); | ||||
| 
 | ||||
|     // check `Others` is checked
 | ||||
|     assert.equal(await driver.find('.test-filter-menu-summary').find('input').matches(':checked'), false); | ||||
|     assert.equal(await driver.find('.test-filter-menu-summary').find('input').matches(':indeterminate'), false); | ||||
| 
 | ||||
|     // Click Apply
 | ||||
|     await driver.find('.test-filter-menu-apply-btn').click(); | ||||
| 
 | ||||
|     // open Count filter menu
 | ||||
|     await driver.findContent('.test-filter-field', /Count/).click(); | ||||
| 
 | ||||
|     // Click all and click Apply
 | ||||
|     await driver.findContent('.test-filter-menu-bulk-action', /All/).click(); | ||||
|     await driver.find('.test-filter-menu-apply-btn').click(); | ||||
| 
 | ||||
|     // open Name filter menu
 | ||||
|     await driver.findContent('.test-filter-field', /Name/).click(); | ||||
| 
 | ||||
|     // Check Apples and Oranges are unchecked
 | ||||
|     assert.deepEqual(await driver.findAll('.test-filter-menu-list label', (e) => e.getText()), | ||||
|                      ['Apples', 'Bananas', 'Clementines', 'Grapefruit', 'Grapes', 'Oranges']); | ||||
|     assert.equal(await findByName('Apples').find('input').matches(':checked'), false); | ||||
|     assert.equal(await findByName('Oranges').find('input').matches(':checked'), false); | ||||
| 
 | ||||
|     // click Apply
 | ||||
|     await driver.find('.test-filter-menu-apply-btn').click(); | ||||
| 
 | ||||
|     // Open count Filter menu
 | ||||
|     await driver.findContent('.test-filter-field', /Count/).click(); | ||||
| 
 | ||||
|     // Check there's only 4 values left
 | ||||
|     assert.deepEqual(await driver.findAll('.test-filter-menu-list label', (e) => e.getText()), | ||||
|                      ['n/a', '-1', '2', '5']); | ||||
| 
 | ||||
|     // Click Others
 | ||||
|     await driver.find('.test-filter-menu-summary').click(); | ||||
| 
 | ||||
|     // click Apply
 | ||||
|     await driver.find('.test-filter-menu-apply-btn').click(); | ||||
| 
 | ||||
|     // Open Name filter menu
 | ||||
|     await driver.findContent('.test-filter-field', /Name/).click(); | ||||
| 
 | ||||
|     // Check Others is unchecked
 | ||||
|     assert.equal(await driver.find('.test-filter-menu-summary').find('input').matches(':checked'), false); | ||||
|     assert.equal(await driver.find('.test-filter-menu-summary').find('input').matches(':indeterminate'), false); | ||||
| 
 | ||||
|     // Click Others
 | ||||
|     await driver.find('.test-filter-menu-summary').find('input').click(); | ||||
|     await driver.find('.test-filter-menu-apply-btn').click(); | ||||
| 
 | ||||
|     // Open count filter
 | ||||
|     await driver.findContent('.test-filter-field', /Count/).click(); | ||||
| 
 | ||||
|     // Click All and click apply
 | ||||
|     await driver.findContent('.test-filter-menu-bulk-action', /All/).click(); | ||||
|     await driver.find('.test-filter-menu-apply-btn').click(); | ||||
| 
 | ||||
|     // open Name filter menu
 | ||||
|     await driver.findContent('.test-filter-field', /Name/).click(); | ||||
| 
 | ||||
|     // Check both apples and orages are not checked
 | ||||
|     assert.equal(await findByName('Apples').find('input').matches(':checked'), false); | ||||
|     assert.equal(await findByName('Oranges').find('input').matches(':checked'), false); | ||||
| 
 | ||||
|     // Revert to all
 | ||||
|     await driver.findContent('.test-filter-menu-bulk-action', /All/).click(); | ||||
|     await driver.find('.test-filter-menu-apply-btn').click(); | ||||
| 
 | ||||
|     // Open Count filter menu and click All
 | ||||
|     await driver.findContent('.test-filter-field', /Count/).click(); | ||||
|     await driver.findContent('.test-filter-menu-bulk-action', /All/).click(); | ||||
|     await driver.find('.test-filter-menu-apply-btn').click(); | ||||
|   }); | ||||
| 
 | ||||
|   it('should show count of unique values next to summaries', async () => { | ||||
| 
 | ||||
|     // add another Apples
 | ||||
|     await driver.find('.record-add .field').click(); | ||||
|     await driver.sendKeys('Apples', Key.ENTER); | ||||
|     await gu.waitForServer(); | ||||
|     assert.deepEqual( | ||||
|       await gu.getVisibleGridCells({cols: ['Name', 'Count'], rowNums: [1, 2, 3, 4, 5, 6, 7]}), | ||||
|       [ 'Apples', '1', | ||||
|         'Oranges', '3', | ||||
|         'Bananas', '2', | ||||
|         'Grapes', '-1', | ||||
|         'Grapefruit', 'n/a', | ||||
|         'Clementines', '5', | ||||
|         'Apples', '0' | ||||
|       ]); | ||||
| 
 | ||||
|     // open the Count filter
 | ||||
|     await driver.findContent('.test-filter-field', /Count/).click(); | ||||
| 
 | ||||
|     // uncheck 0 and 1
 | ||||
|     await findByName(/^0/).click(); | ||||
|     await findByName(/^1/).click(); | ||||
| 
 | ||||
|     // Click Apply
 | ||||
|     await driver.find('.test-filter-menu-apply-btn').click(); | ||||
| 
 | ||||
|     // open the Name filter
 | ||||
|     await driver.findContent('.test-filter-field', /Name/).click(); | ||||
| 
 | ||||
|     // check Apples is missing
 | ||||
|     assert.deepEqual(await driver.findAll('.test-filter-menu-list label', (e) => e.getText()), | ||||
|                      ['Bananas', 'Clementines', 'Grapefruit', 'Grapes', 'Oranges']); | ||||
| 
 | ||||
|     // check count is (1)
 | ||||
|     assert.deepEqual( | ||||
|       await driver.findAll('.test-filter-menu-summary', (e) => e.find('label').getText()), | ||||
|       ['Others (1)'] | ||||
|     ); | ||||
| 
 | ||||
|     // close filter
 | ||||
|     await driver.sendKeys(Key.ESCAPE); | ||||
|   }); | ||||
| 
 | ||||
|   it('should show a working range filter for numeric columns', async function() { | ||||
| 
 | ||||
|     // open the Count filter
 | ||||
|     await driver.findContent('.test-filter-field', /Count/).click(); | ||||
| 
 | ||||
|     // set min to '2'
 | ||||
|     await gu.setRangeFilterBound('min', '2'); | ||||
|     await driver.find('.test-filter-menu-apply-btn').click(); | ||||
| 
 | ||||
|     // check values
 | ||||
|     assert.deepEqual( | ||||
|       await gu.getVisibleGridCells({cols: ['Name', 'Count'], rowNums: [1, 2, 3, 4]}), | ||||
|       [ 'Oranges', '3', | ||||
|         'Bananas', '2', | ||||
|         'Clementines', '5', | ||||
|         '', '' | ||||
|       ] | ||||
|     ); | ||||
| 
 | ||||
|     // reopen the filter
 | ||||
|     await driver.findContent('.test-filter-field', /Count/).click(); | ||||
| 
 | ||||
|     // set max to '4'
 | ||||
|     await gu.setRangeFilterBound('max', '4'); | ||||
|     await driver.find('.test-filter-menu-apply-btn').click(); | ||||
| 
 | ||||
|     assert.deepEqual( | ||||
|       await gu.getVisibleGridCells({cols: ['Name', 'Count'], rowNums: [1, 2, 3, 4]}), | ||||
|       [ 'Oranges', '3', | ||||
|         'Bananas', '2', | ||||
|         '', '', | ||||
|         undefined, undefined | ||||
|       ] | ||||
|     ); | ||||
| 
 | ||||
|     // remove both min and max
 | ||||
|     await driver.findContent('.test-filter-field', /Count/).click(); | ||||
|     await gu.setRangeFilterBound('min', null); | ||||
|     await gu.setRangeFilterBound('max', null); | ||||
|     await driver.find('.test-filter-menu-apply-btn').click(); | ||||
| 
 | ||||
|     // check all values are there
 | ||||
|     assert.deepEqual( | ||||
|       await gu.getVisibleGridCells({cols: ['Name', 'Count'], rowNums: [1, 2, 3, 4, 5, 6, 7]}), | ||||
|       [ 'Apples', '1', | ||||
|         'Oranges', '3', | ||||
|         'Bananas', '2', | ||||
|         'Grapes', '-1', | ||||
|         'Grapefruit', 'n/a', | ||||
|         'Clementines', '5', | ||||
|         'Apples', '0' | ||||
|       ]); | ||||
| 
 | ||||
|   }); | ||||
| 
 | ||||
|   it('should remove new filters when Cancel is clicked in a new filter', async function() { | ||||
|     // Create a new Date filter.
 | ||||
|     await gu.openColumnMenu('Date', 'Filter'); | ||||
|     assert.deepEqual( | ||||
|       [ | ||||
|         {checked: true, value: 'n/a', count: 1}, | ||||
|         {checked: true, value: '', count: 2}, | ||||
|         {checked: true, value: '2019-07-15', count: 1}, | ||||
|         {checked: true, value: '2019-07-16', count: 1}, | ||||
|         {checked: true, value: '2019-07-17', count: 1}, | ||||
|         {checked: true, value: '2019-07-18', count: 1} | ||||
|       ], | ||||
|       await gu.getFilterMenuState() | ||||
|     ); | ||||
| 
 | ||||
|     // Check that the Date filter is pinned.
 | ||||
|     assert.deepEqual( | ||||
|       [ | ||||
|         {name: 'Name', hasUnsavedChanges: true}, | ||||
|         {name: 'Count', hasUnsavedChanges: true}, | ||||
|         {name: 'Date', hasUnsavedChanges: true}, | ||||
|       ], | ||||
|       await gu.getPinnedFilters() | ||||
|     ); | ||||
| 
 | ||||
|     // Set a min filter of '2019-07-16'.
 | ||||
|     await gu.setRangeFilterBound('min', '2019-07-16'); | ||||
| 
 | ||||
|     // Click Cancel, and check that the filter is no longer applied to the table data.
 | ||||
|     await gu.waitToPass(async () => { | ||||
|       await driver.find('.test-filter-menu-cancel-btn').click(); | ||||
|       assert.isFalse(await driver.find('.test-filter-menu-wrapper').isPresent()); | ||||
|     }); | ||||
|     assert.deepEqual( | ||||
|       await gu.getVisibleGridCells({cols: ['Name', 'Count'], rowNums: [1, 2, 3, 4, 5, 6, 7]}), | ||||
|       [ 'Apples', '1', | ||||
|         'Oranges', '3', | ||||
|         'Bananas', '2', | ||||
|         'Grapes', '-1', | ||||
|         'Grapefruit', 'n/a', | ||||
|         'Clementines', '5', | ||||
|         'Apples', '0' | ||||
|       ] | ||||
|     ); | ||||
| 
 | ||||
|     // Check that the Date filter was removed.
 | ||||
|     await gu.openSectionMenu('sortAndFilter'); | ||||
|     assert.isFalse(await driver.findContent('.test-filter-config-filter', /Date/).isPresent()); | ||||
|     await gu.sendKeys(Key.ESCAPE); | ||||
|     assert.deepEqual( | ||||
|       [ | ||||
|         {name: 'Name', hasUnsavedChanges: true}, | ||||
|         {name: 'Count', hasUnsavedChanges: true}, | ||||
|       ], | ||||
|       await gu.getPinnedFilters() | ||||
|     ); | ||||
|   }); | ||||
| 
 | ||||
|   it('should revert to open state when Cancel is clicked in an existing filter', async function() { | ||||
|     // Open the Count filter.
 | ||||
|     await driver.findContent('.test-filter-field', /Count/).click(); | ||||
| 
 | ||||
|     // Filter out 1 and 2.
 | ||||
|     await driver.findContent('.test-filter-menu-list label', /1/).click(); | ||||
|     await driver.findContent('.test-filter-menu-list label', /2/).click(); | ||||
| 
 | ||||
|     // Unpin the filter.
 | ||||
|     await driver.find('.test-filter-menu-pin-btn').click(); | ||||
| 
 | ||||
|     // Click Cancel, and check that the filter is no longer applied to the table data.
 | ||||
|     await driver.find('.test-filter-menu-cancel-btn').click(); | ||||
|     assert.deepEqual( | ||||
|       await gu.getVisibleGridCells({cols: ['Name', 'Count'], rowNums: [1, 2, 3, 4, 5, 6, 7]}), | ||||
|       [ 'Apples', '1', | ||||
|         'Oranges', '3', | ||||
|         'Bananas', '2', | ||||
|         'Grapes', '-1', | ||||
|         'Grapefruit', 'n/a', | ||||
|         'Clementines', '5', | ||||
|         'Apples', '0' | ||||
|       ] | ||||
|     ); | ||||
| 
 | ||||
|     // Check that Count is still pinned to the filter bar.
 | ||||
|     assert.deepEqual( | ||||
|       [ | ||||
|         {name: 'Name', hasUnsavedChanges: true}, | ||||
|         {name: 'Count', hasUnsavedChanges: true}, | ||||
|       ], | ||||
|       await gu.getPinnedFilters() | ||||
|     ); | ||||
| 
 | ||||
|     // Check the filter menu state of Count.
 | ||||
|     await driver.findContent('.test-filter-field', /Count/).click(); | ||||
|     assert.deepEqual( | ||||
|       [ | ||||
|         {checked: true, value: 'n/a', count: 1}, | ||||
|         {checked: true, value: '-1', count: 1}, | ||||
|         {checked: true, value: '0', count: 1}, | ||||
|         {checked: true, value: '1', count: 1}, | ||||
|         {checked: true, value: '2', count: 1}, | ||||
|         {checked: true, value: '3', count: 1}, | ||||
|         {checked: true, value: '5', count: 1}, | ||||
|       ], | ||||
|       await gu.getFilterMenuState() | ||||
|     ); | ||||
| 
 | ||||
|     await gu.sendKeys(Key.ESCAPE); | ||||
|   }); | ||||
| 
 | ||||
|   async function testDateLikeColumn(colId: 'Date'|'DateTime') { | ||||
| 
 | ||||
|     const timeChunk = colId === 'DateTime' ? ' 12:00am' : ''; | ||||
|     const colRegex = new RegExp(colId + '\\b'); | ||||
| 
 | ||||
|     // add Date Filter
 | ||||
|     await driver.find('.test-add-filter-btn').click(); | ||||
|     await driver.findContent('.grist-floating-menu li', colRegex).click(); | ||||
| 
 | ||||
|     // set min to '2019-07-16'
 | ||||
|     await gu.setRangeFilterBound('min', '2019-07-16'); | ||||
|     await driver.find('.test-filter-menu-apply-btn').click(); | ||||
|     await gu.waitAppFocus(true); | ||||
| 
 | ||||
|     // check values
 | ||||
|     assert.deepEqual( | ||||
|       await gu.getVisibleGridCells({cols: ['Name', colId], rowNums: [1, 2, 3, 4]}), | ||||
|       [ 'Apples', '2019-07-17' + timeChunk, | ||||
|         'Oranges', '2019-07-16' + timeChunk, | ||||
|         'Bananas', '2019-07-18' + timeChunk, | ||||
|         '', '' | ||||
|       ] | ||||
|     ); | ||||
| 
 | ||||
|     // reopen the filter
 | ||||
|     await driver.findContent('.test-filter-field', colRegex).click(); | ||||
| 
 | ||||
|     // set max to '2019-07-17'
 | ||||
|     await gu.setRangeFilterBound('max', '2019-07-17'); | ||||
|     await driver.find('.test-filter-menu-apply-btn').click(); | ||||
|     await gu.waitAppFocus(true); | ||||
| 
 | ||||
|     assert.deepEqual( | ||||
|       await gu.getVisibleGridCells({cols: ['Name', colId], rowNums: [1, 2, 3, 4]}), | ||||
|       [ 'Apples', '2019-07-17' + timeChunk, | ||||
|         'Oranges', '2019-07-16' + timeChunk, | ||||
|         '', '', | ||||
|         undefined, undefined | ||||
|       ] | ||||
|     ); | ||||
| 
 | ||||
|     // remove both min and max
 | ||||
|     await driver.findContent('.test-filter-field', colRegex).click(); | ||||
|     await gu.setRangeFilterBound('min', null); | ||||
|     await gu.setRangeFilterBound('max', null); | ||||
|     await driver.find('.test-filter-menu-apply-btn').click(); | ||||
|     await gu.waitAppFocus(true); | ||||
| 
 | ||||
|     // check all values are there
 | ||||
|     assert.deepEqual( | ||||
|       await gu.getVisibleGridCells({cols: ['Name', colId], rowNums: [1, 2, 3, 4, 5, 6, 7]}), | ||||
|       [ 'Apples',      '2019-07-17' + timeChunk, | ||||
|         'Oranges',     '2019-07-16' + timeChunk, | ||||
|         'Bananas',     '2019-07-18' + timeChunk, | ||||
|         'Grapes',      '', | ||||
|         'Grapefruit',  '2019-07-15' + timeChunk, | ||||
|         'Clementines', 'n/a', | ||||
|         'Apples', '', | ||||
|       ]); | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   it('should show a working range filter for Date column', async function() { | ||||
|     await testDateLikeColumn('Date'); | ||||
|   }); | ||||
| 
 | ||||
|   it('should show a working range filter for DateTime column', async function() { | ||||
| 
 | ||||
|     // adds a DateTime column
 | ||||
|     await api.applyUserActions(doc.id, [ | ||||
|       ['AddVisibleColumn', 'Table1', 'DateTime', { | ||||
|         type: "DateTime:UTC", widgetOptions: '{"dateFormat": "YYYY-MM-DD", "timeFormat": "h:mma"}' | ||||
|       }], | ||||
|       ['BulkUpdateRecord', 'Table1', [1, 2, 3, 4, 5, 6], { | ||||
|         DateTime: [ | ||||
|           // TODO: fix timezone
 | ||||
|           "2019-07-17T00:00Z", | ||||
|           "2019-07-16T00:00Z", | ||||
|           "2019-07-18T00:00Z", | ||||
|           "", | ||||
|           "2019-07-15T00:00Z", | ||||
|           "n/a", | ||||
|         ] | ||||
|       }], | ||||
|     ]); | ||||
| 
 | ||||
|     await testDateLikeColumn('DateTime'); | ||||
|   }); | ||||
| 
 | ||||
|   it('should have working date range filter also when column is hidden', async function() { | ||||
| 
 | ||||
|     // hide Date column
 | ||||
|     await gu.toggleSidePanel('right', 'open'); | ||||
|     await driver.find('.test-right-tab-pagewidget').click(); | ||||
|     await gu.moveToHidden('Date'); | ||||
| 
 | ||||
|     // add Date filter
 | ||||
|     await driver.findContent('.test-filter-field', 'Date').click(); | ||||
| 
 | ||||
|     // start typing date in min bounds and send TAB
 | ||||
|     await driver.find('.test-filter-menu-min').click(); | ||||
|     await gu.sendKeys('2019-07-14', Key.TAB); | ||||
| 
 | ||||
|     // check min is set to a valid date
 | ||||
|     assert.equal(await driver.find('.test-filter-menu-min input').value(), '2019-07-14'); | ||||
|   }); | ||||
| 
 | ||||
| }); | ||||
							
								
								
									
										120
									
								
								test/nbrowser/ColumnFilterMenu2.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								test/nbrowser/ColumnFilterMenu2.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,120 @@ | ||||
| import * as gu from 'test/nbrowser/gristUtils'; | ||||
| import { setupTestSuite } from "test/nbrowser/testUtils"; | ||||
| import { assert, driver } from 'mocha-webdriver'; | ||||
| 
 | ||||
| 
 | ||||
| function getItems() { | ||||
|   return driver.findAll('.test-filter-menu-list label', async (e) => ({ | ||||
|     checked: await e.find('input').isSelected(), | ||||
|     label: await e.getText(), | ||||
|     count: await e.findClosest('div').find('.test-filter-menu-count').getText() | ||||
|   })); | ||||
| } | ||||
| 
 | ||||
| describe('ColumnFilterMenu2', function() { | ||||
| 
 | ||||
|   this.timeout(20000); | ||||
|   const cleanup = setupTestSuite(); | ||||
|   let mainSession: gu.Session; | ||||
|   let docId: string; | ||||
|   let api: any; | ||||
| 
 | ||||
|   before(async function() { | ||||
|     mainSession = await gu.session().teamSite.user('user1').login(); | ||||
|     docId = await mainSession.tempNewDoc(cleanup, 'ColumnFilterMenu2.grist', {load: false}); | ||||
|     api = mainSession.createHomeApi(); | ||||
|     // Prepare a table with some interestingly-formatted columns, and some data.
 | ||||
|     await api.applyUserActions(docId, [ | ||||
|       ['AddTable', 'Test', []], | ||||
|       ['AddVisibleColumn', 'Test', 'Bool', { | ||||
|         type: 'Bool', widgetOptions: JSON.stringify({widget:"TextBox"}) | ||||
|       }], | ||||
|       ['AddVisibleColumn', 'Test', 'Choice', { | ||||
|         type: 'Choice', widgetOptions: JSON.stringify({choices: ['foo', 'bar']}) | ||||
|       }], | ||||
|       ['AddVisibleColumn', 'Test', 'ChoiceList', { | ||||
|         type: 'ChoiceList', widgetOptions: JSON.stringify({choices: ['foo', 'bar']}) | ||||
|       }], | ||||
|       ['AddRecord', 'Test', null, {Bool: true, Choice: 'foo', ChoiceList: ['L', 'foo']}], | ||||
|     ]); | ||||
|     return docId; | ||||
|   }); | ||||
| 
 | ||||
|   afterEach(() => gu.checkForErrors()); | ||||
| 
 | ||||
|   it('should show all options for Bool columns', async () => { | ||||
|     await mainSession.loadDoc(`/doc/${docId}/p/2`); | ||||
| 
 | ||||
|     await gu.openColumnMenu('Bool', 'Filter'); | ||||
|     assert.deepEqual(await getItems(), [ | ||||
|       {checked: true, label: 'false', count: '0'}, | ||||
|       {checked: true, label: 'true', count: '1'}, | ||||
|     ]); | ||||
| 
 | ||||
|     // click false
 | ||||
|     await driver.findContent('.test-filter-menu-list label', 'false').click(); | ||||
|     assert.deepEqual(await getItems(), [ | ||||
|       {checked: false, label: 'false', count: '0'}, | ||||
|       {checked: true, label: 'true', count: '1'}, | ||||
|     ]); | ||||
| 
 | ||||
|     // add new record with Bool=false
 | ||||
|     const {retValues} = await api.applyUserActions(docId, [ | ||||
|       ['AddRecord', 'Test', null, {Bool: false}], | ||||
|     ]); | ||||
| 
 | ||||
|     // check record is not shown on screen
 | ||||
|     assert.deepEqual( | ||||
|       await gu.getVisibleGridCells({cols: ['Bool', 'Choice', 'ChoiceList'], rowNums: [1, 2]}), | ||||
|       ['true', 'foo', 'foo', | ||||
|        '', '', '' | ||||
|       ] as any | ||||
|     ); | ||||
| 
 | ||||
|     // remove added record
 | ||||
|     await api.applyUserActions(docId, [ | ||||
|       ['RemoveRecord', 'Test', retValues[0]] | ||||
|     ]); | ||||
|   }); | ||||
| 
 | ||||
|   it('should show all options for Choice/ChoiceList columns', async () => { | ||||
|     await gu.openColumnMenu('Choice', 'Filter'); | ||||
|     assert.deepEqual(await getItems(), [ | ||||
|       {checked: true, label: 'bar', count: '0'}, | ||||
|       {checked: true, label: 'foo', count: '1'}, | ||||
|     ]); | ||||
| 
 | ||||
|     // click bar
 | ||||
|     await driver.findContent('.test-filter-menu-list label', 'bar').click(); | ||||
|     assert.deepEqual(await getItems(), [ | ||||
|       {checked: false, label: 'bar', count: '0'}, | ||||
|       {checked: true, label: 'foo', count: '1'}, | ||||
|     ]); | ||||
| 
 | ||||
|     // add new record with Choice=bar
 | ||||
|     const {retValues} = await api.applyUserActions(docId, [ | ||||
|       ['AddRecord', 'Test', null, {Choice: 'bar'}], | ||||
|     ]); | ||||
| 
 | ||||
|     // check record is not shown on screen
 | ||||
|     assert.deepEqual( | ||||
|       await gu.getVisibleGridCells({cols: ['Bool', 'Choice', 'ChoiceList'], rowNums: [1, 2]}), | ||||
|       ['true', 'foo', 'foo', | ||||
|        '', '', '' | ||||
|       ] as any | ||||
|     ); | ||||
| 
 | ||||
|     // remove added record
 | ||||
|     await api.applyUserActions(docId, [ | ||||
|       ['RemoveRecord', 'Test', retValues[0]] | ||||
|     ]); | ||||
| 
 | ||||
|     // check ChoiceList filter offeres all options
 | ||||
|     await gu.openColumnMenu('ChoiceList', 'Filter'); | ||||
|     assert.deepEqual(await getItems(), [ | ||||
|       {checked: true, label: 'bar', count: '0'}, | ||||
|       {checked: true, label: 'foo', count: '1'}, | ||||
|     ]); | ||||
|   }); | ||||
| 
 | ||||
| }); | ||||
							
								
								
									
										211
									
								
								test/nbrowser/ColumnFilterMenu3.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								test/nbrowser/ColumnFilterMenu3.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,211 @@ | ||||
| import { assert, driver, Key } from "mocha-webdriver"; | ||||
| import * as gu from 'test/nbrowser/gristUtils'; | ||||
| import { setupTestSuite } from "test/nbrowser/testUtils"; | ||||
| 
 | ||||
| void(driver); | ||||
| void(Key); | ||||
| 
 | ||||
| async function getValues() { | ||||
|   return driver.findAll('.test-filter-menu-list label', e => e.getText()); | ||||
| } | ||||
| 
 | ||||
| describe('ColumnFilterMenu3', function() { | ||||
|   this.timeout(30000); | ||||
|   const cleanup = setupTestSuite(); | ||||
|   let mainSession: gu.Session; | ||||
|   let docId: string; | ||||
|   before(async () => { | ||||
|     mainSession = await gu.session().teamSite.user('user1').login(); | ||||
|     docId = await mainSession.tempNewDoc(cleanup, 'Search3.grist', {load: false}); | ||||
|     const api = mainSession.createHomeApi(); | ||||
|     // Prepare a table with some interestingly-formatted columns, and some data.
 | ||||
|     const {retValues} = await api.applyUserActions(docId, [ | ||||
|       ['AddTable', 'Test', []], | ||||
|       ['AddVisibleColumn', 'Test', 'Date', {type: 'Date', widgetOptions: '{"dateFormat":"DD-MM-YYYY"}'}], | ||||
|       ['AddVisibleColumn', 'Test', 'Numeric', {type: 'Numeric'}], | ||||
|       ['AddVisibleColumn', 'Test', 'Int', {type: 'Int'}], | ||||
|       ['AddVisibleColumn', 'Test', 'Ref', {type: 'Ref:Test'}], | ||||
|       ['AddVisibleColumn', 'Test', 'RefList', {type: 'RefList:Test'}], | ||||
|     ]); | ||||
|     await api.applyUserActions(docId, [ | ||||
|       ['UpdateRecord', '_grist_Tables_column', retValues[4].colRef, {visibleCol: retValues[1].colRef}], | ||||
|       ['UpdateRecord', '_grist_Tables_column', retValues[5].colRef, {visibleCol: retValues[1].colRef}], | ||||
|       ['SetDisplayFormula', 'Test', null, retValues[4].colRef, '$Ref.Date'], | ||||
|       ['SetDisplayFormula', 'Test', null, retValues[5].colRef, '$RefList.Date'], | ||||
|       ['AddRecord', 'Test', null, {Date: '22-12-2011', Numeric: 2,  Int: 2,  Ref: 1, | ||||
|                                    RefList: ['L', 1, 2]}], | ||||
|       ['AddRecord', 'Test', null, {Date: '20-12-2021', Numeric: 22, Int: 22, Ref: 2, | ||||
|                                    RefList: ['L', 1]}], | ||||
|       ['AddRecord', 'Test', null, {Date: '20-12-2011', Numeric: 3,  Int: 3,  Ref: 3, | ||||
|                                    RefList: ['L', 1, 2, 3]}], | ||||
|     ]); | ||||
|     await mainSession.loadDoc(`/doc/${docId}/p/2`); | ||||
|   }); | ||||
| 
 | ||||
|   afterEach(async () => { | ||||
|     // close menu if one was opened
 | ||||
|     if (await driver.find('.grist-floating-menu').isPresent()) { | ||||
|       await driver.sendKeys(Key.ESCAPE); | ||||
|     } | ||||
|     if (await driver.find('.test-filter-menu-wrapper').isPresent()) { | ||||
|       await driver.sendKeys(Key.ESCAPE); | ||||
|     } | ||||
|   }); | ||||
| 
 | ||||
|   it('should correctly focus between inputs in Numeric columns', async () => { | ||||
|     // A bug was introduced where the search input could no longer be focused if either range
 | ||||
|     // input had focus.
 | ||||
|     await gu.openColumnMenu('Numeric', 'Filter'); | ||||
| 
 | ||||
|     const assertSearchCanBeFocused = async () => { | ||||
|       await driver.find('.test-filter-menu-search-input').click(); | ||||
|       assert.equal( | ||||
|         await driver.switchTo().activeElement().getId(), | ||||
|         await driver.find('.test-filter-menu-search-input').getId() | ||||
|       ); | ||||
|     }; | ||||
| 
 | ||||
|     await driver.find('.test-filter-menu-min').click(); | ||||
|     await assertSearchCanBeFocused(); | ||||
|     await driver.find('.test-filter-menu-max').click(); | ||||
|     await assertSearchCanBeFocused(); | ||||
|   }); | ||||
| 
 | ||||
|   it('should have correct order for Numeric column', async () => { | ||||
|     await gu.openColumnMenu('Numeric', 'Filter'); | ||||
|     assert.deepEqual(await getValues(), ['2', '3', '22']); | ||||
|   }); | ||||
| 
 | ||||
|   it('should have correct order for Integer column', async () => { | ||||
|     await gu.openColumnMenu('Int', 'Filter'); | ||||
|     assert.deepEqual(await getValues(), ['2', '3', '22']); | ||||
|     await driver.find('.test-filter-menu-apply-btn'); | ||||
|   }); | ||||
| 
 | ||||
|   it('should have correct order for Date column', async () => { | ||||
|     await gu.openColumnMenu('Date', 'Filter'); | ||||
|     assert.deepEqual(await getValues(), ['20-12-2011', '22-12-2011', '20-12-2021']); | ||||
|   }); | ||||
| 
 | ||||
|   describe('Ref', function() { | ||||
| 
 | ||||
|     it('should have correct order for Numeric column', async () => { | ||||
|       await gu.toggleSidePanel('right', 'open'); | ||||
|       await gu.openColumnMenu('Ref', 'Options'); | ||||
|       await gu.setRefShowColumn('Numeric'); | ||||
|       await gu.openColumnMenu('Ref', 'Filter'); | ||||
|       assert.deepEqual(await getValues(), ['2', '3', '22']); | ||||
|     }); | ||||
|     it('should have correct order for Integer column', async () => { | ||||
|       await gu.setRefShowColumn('Int'); | ||||
|       await gu.openColumnMenu('Ref', 'Filter'); | ||||
|       assert.deepEqual(await getValues(), ['2', '3', '22']); | ||||
|     }); | ||||
|     it('should have correct order for Date column', async () => { | ||||
|       await gu.setRefShowColumn('Date'); | ||||
|       await gu.openColumnMenu('Ref', 'Filter'); | ||||
|       assert.deepEqual(await getValues(), ['20-12-2011', '22-12-2011', '20-12-2021']); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('RefList', function() { | ||||
|     it('should have correct order for Numeric column', async () => { | ||||
|       await gu.openColumnMenu('RefList', 'Options'); | ||||
|       await gu.setRefShowColumn('Numeric'); | ||||
|       await gu.openColumnMenu('RefList', 'Filter'); | ||||
|       assert.deepEqual(await getValues(), ['2', '3', '22']); | ||||
|     }); | ||||
|     it('should have correct order for Integer column', async () => { | ||||
|       await gu.setRefShowColumn('Int'); | ||||
|       await gu.openColumnMenu('RefList', 'Filter'); | ||||
|       assert.deepEqual(await getValues(), ['2', '3', '22']); | ||||
|     }); | ||||
|     it('should have correct order for Date column', async () => { | ||||
|       await gu.setRefShowColumn('Date'); | ||||
|       await gu.openColumnMenu('RefList', 'Filter'); | ||||
|       assert.deepEqual(await getValues(), ['20-12-2011', '22-12-2011', '20-12-2021']); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('id mismatch', function() { | ||||
|     // This test intent to replicate a bug that happened with filters. For the bug to happen we need
 | ||||
|     // to have a view field row id (here view field of col B) that matches the row id of another
 | ||||
|     // column (here col A). When this happen, and when col A is hidden, and when users open the
 | ||||
|     // column menu for B, the filter apply mistakingly to column A values as well, which could
 | ||||
|     // intail unexpected result depending on the values of A.
 | ||||
| 
 | ||||
|     let docId2: string; | ||||
|     before(async () => { | ||||
|       docId2 = await mainSession.tempNewDoc(cleanup, 'ColumnFilterMenu3IdMismatch.grist', {load: false}); | ||||
|       const api = mainSession.createHomeApi(); | ||||
|       await api.applyUserActions(docId2, [ | ||||
|         ['BulkAddRecord', 'Table1', [null, null, null], {A: [1, 3, 3], B: [1, 1, 3]}], | ||||
|         ['RemoveRecord', "_grist_Views_section_field", 1], // Hide 'A' column
 | ||||
|       ]); | ||||
|     }); | ||||
|     it('filters should work correctly', async function() { | ||||
|       await mainSession.loadDoc(`/doc/${docId2}/p/1`); | ||||
| 
 | ||||
|       // filter B by {max: 2}
 | ||||
|       await gu.openColumnMenu('B', 'Filter'); | ||||
|       await gu.setRangeFilterBound('max', '2'); | ||||
|       await driver.find('.test-filter-menu-apply-btn').click(); | ||||
| 
 | ||||
|       // check filter does not behaves in-correctly (here mostly to show what the problem looked
 | ||||
|       // like)
 | ||||
|       assert.notDeepEqual( | ||||
|         await gu.getVisibleGridCells({cols: ['B'], rowNums: [1, 2, 3]}), | ||||
|         [ '1', '', undefined] | ||||
|       ); | ||||
| 
 | ||||
|       // check filter does behave correctly
 | ||||
|       assert.deepEqual( | ||||
|         await gu.getVisibleGridCells({cols: ['B'], rowNums: [1, 2, 3]}), | ||||
|         [ '1', '1', ''] | ||||
|       ); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('empty choice columns', function() { | ||||
|     // Previously, a bug would cause an error to be thrown when filtering an empty
 | ||||
|     // choice or choice list column. This suite replicates that scenario.
 | ||||
| 
 | ||||
|     async function assertEmptyRowCount(count: number) { | ||||
|       assert.deepEqual( | ||||
|         await driver.findAll('.test-filter-menu-list label', (e) => e.getText()), | ||||
|         [''] | ||||
|       ); | ||||
|       assert.deepEqual( | ||||
|         await driver.findAll('.test-filter-menu-list .test-filter-menu-count', (e) => e.getText()), | ||||
|         [count.toString()], | ||||
|       ); | ||||
|     } | ||||
| 
 | ||||
|     async function assertEmptyColumnIsFilterable( | ||||
|       columnType: 'Choice' | 'Choice List' | 'Reference List' | ||||
|     ) { | ||||
|       const columnLabel = `Empty ${columnType}`; | ||||
|       await gu.addColumn(columnLabel); | ||||
|       await gu.setType(new RegExp(`${columnType}$`)); | ||||
|       await gu.openColumnMenu(columnLabel, 'Filter'); | ||||
|       await assertEmptyRowCount(2); | ||||
|       await gu.sendKeys(Key.ESCAPE); | ||||
|     } | ||||
| 
 | ||||
|     afterEach(() => gu.checkForErrors()); | ||||
| 
 | ||||
|     it('should not throw an error when filtering empty choice columns', async function() { | ||||
|       await assertEmptyColumnIsFilterable('Choice'); | ||||
|     }); | ||||
| 
 | ||||
|     it('should not throw an error when filtering empty choice list columns', async function() { | ||||
|       await assertEmptyColumnIsFilterable('Choice List'); | ||||
|     }); | ||||
| 
 | ||||
|     it('should not throw an error when filtering empty reference list columns', async function() { | ||||
|       // Note: this wasn't impacted by the aforementioned bug; this test is only included for
 | ||||
|       // completeness.
 | ||||
|       await assertEmptyColumnIsFilterable('Reference List'); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
							
								
								
									
										531
									
								
								test/nbrowser/SectionFilter.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										531
									
								
								test/nbrowser/SectionFilter.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,531 @@ | ||||
| import {assert, driver, Key, until} from 'mocha-webdriver'; | ||||
| import * as gu from 'test/nbrowser/gristUtils'; | ||||
| import {setupTestSuite} from 'test/nbrowser/testUtils'; | ||||
| 
 | ||||
| describe('SectionFilter', function() { | ||||
|   this.timeout(60000); | ||||
|   const cleanup = setupTestSuite(); | ||||
| 
 | ||||
|   describe('Core tests', function() { | ||||
| 
 | ||||
|     before(async function() { | ||||
|       this.timeout(10000); | ||||
|       const session = await gu.session().teamSite.login(); | ||||
|       await session.tempNewDoc(cleanup); | ||||
|     }); | ||||
| 
 | ||||
|     it('should be able to open / close filter menu', async () => { | ||||
|       const menu = await gu.openColumnMenu('A', 'Filter'); | ||||
|       assert.equal(await menu.find('.test-filter-menu-list').getText(), 'No matching values'); | ||||
|       await driver.sendKeys(Key.ESCAPE); | ||||
|       await driver.wait(until.stalenessOf(menu)); | ||||
|     }); | ||||
| 
 | ||||
|     it('should filter out records in response to filter menu selections', async () => { | ||||
|       this.timeout(10000); | ||||
| 
 | ||||
|       await gu.enterGridRows({col: 'A', rowNum: 1}, [ | ||||
|         ['Apples',  '1'], | ||||
|         ['Oranges', '2'], | ||||
|         ['Bananas', '1'], | ||||
|         ['Apples',  '2'], | ||||
|         ['Bananas', '1'], | ||||
|         ['Apples',  '2'], | ||||
|       ]); | ||||
| 
 | ||||
|       const menu = await gu.openColumnMenu('A', 'Filter'); | ||||
|       assert.deepEqual(await gu.getFilterMenuState(), [ | ||||
|         { checked: true, value: 'Apples', count: 3}, | ||||
|         { checked: true, value: 'Bananas', count: 2}, | ||||
|         { checked: true, value: 'Oranges', count: 1} | ||||
|       ]); | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(0, [1, 2, 3, 4, 5, 6]), | ||||
|         ['Apples', 'Oranges', 'Bananas', 'Apples', 'Bananas', 'Apples']); | ||||
| 
 | ||||
|       await menu.findContent('label', /Apples/).click(); | ||||
|       assert.deepEqual(await gu.getFilterMenuState(), [ | ||||
|         { checked: false, value: 'Apples', count: 3}, | ||||
|         { checked: true, value: 'Bananas', count: 2}, | ||||
|         { checked: true, value: 'Oranges', count: 1} | ||||
|       ]); | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(0, [1, 2, 3]), | ||||
|         ['Oranges', 'Bananas', 'Bananas']); | ||||
| 
 | ||||
|       await menu.findContent('label', /Apples/).click(); | ||||
|       assert.deepEqual(await gu.getFilterMenuState(), [ | ||||
|         { checked: true, value: 'Apples', count: 3}, | ||||
|         { checked: true, value: 'Bananas', count: 2}, | ||||
|         { checked: true, value: 'Oranges', count: 1} | ||||
|       ]); | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(0, [1, 2, 3, 4, 5, 6]), | ||||
|         ['Apples', 'Oranges', 'Bananas', 'Apples', 'Bananas', 'Apples']); | ||||
| 
 | ||||
|       await driver.sendKeys(Key.ESCAPE); | ||||
|     }); | ||||
| 
 | ||||
|     it('should undo filter changes on cancel', async () => { | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(0, [1, 2, 3, 4, 5, 6]), | ||||
|         ['Apples', 'Oranges', 'Bananas', 'Apples', 'Bananas', 'Apples']); | ||||
| 
 | ||||
|       const menu = await gu.openColumnMenu('A', 'Filter'); | ||||
| 
 | ||||
|       await menu.findContent('label', /Apples/).click(); | ||||
|       assert.deepEqual(await gu.getFilterMenuState(), [ | ||||
|         { checked: false, value: 'Apples', count: 3}, | ||||
|         { checked: true, value: 'Bananas', count: 2}, | ||||
|         { checked: true, value: 'Oranges', count: 1} | ||||
|       ]); | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(0, [1, 2, 3]), | ||||
|         ['Oranges', 'Bananas', 'Bananas']); | ||||
| 
 | ||||
|       await menu.find('.test-filter-menu-cancel-btn').click(); | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(0, [1, 2, 3, 4, 5, 6]), | ||||
|         ['Apples', 'Oranges', 'Bananas', 'Apples', 'Bananas', 'Apples']); | ||||
|     }); | ||||
| 
 | ||||
|     it('should display new/updated rows even when only certain values are filtered in', async () => { | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(0, [1, 2, 3, 4, 5, 6]), | ||||
|         ['Apples', 'Oranges', 'Bananas', 'Apples', 'Bananas', 'Apples']); | ||||
| 
 | ||||
|       let menu = await gu.openColumnMenu('A', 'Filter'); | ||||
| 
 | ||||
|       // Put the filter into the "inclusion" state, with nothing selected initially.
 | ||||
|       assert.deepEqual( | ||||
|         await driver.findAll('.test-filter-menu-bulk-action:not(:disabled)', (e) => e.getText()), | ||||
|         ['None']); | ||||
|       await driver.findContent('.test-filter-menu-bulk-action', /None/).click(); | ||||
|       assert.deepEqual( | ||||
|         await driver.findAll('.test-filter-menu-bulk-action:not(:disabled)', (e) => e.getText()), | ||||
|         ['All']); | ||||
| 
 | ||||
|       // Include only "Apples".
 | ||||
|       await menu.findContent('label', /Apples/).click(); | ||||
|       assert.deepEqual(await gu.getFilterMenuState(), [ | ||||
|         { checked: true, value: 'Apples', count: 3}, | ||||
|         { checked: false, value: 'Bananas', count: 2}, | ||||
|         { checked: false, value: 'Oranges', count: 1} | ||||
|       ]); | ||||
| 
 | ||||
|       await driver.find('.test-filter-menu-apply-btn').click(); | ||||
| 
 | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(0, [1, 2, 3, 4]), | ||||
|         ['Apples', 'Apples', 'Apples', '']); | ||||
| 
 | ||||
|       // Update first row to Oranges; it should remain shown.
 | ||||
|       await gu.getCell(0, 1).click(); | ||||
|       await gu.enterCell('Oranges'); | ||||
| 
 | ||||
|       // Enter a new row using a keyboard shortcut.
 | ||||
|       await driver.find('body').sendKeys(Key.chord(await gu.modKey(), Key.ENTER)); | ||||
| 
 | ||||
|       // Enter a new row by typing in a value into the "add-row".
 | ||||
|       await driver.find('.gridview_row .record-add .field').click(); | ||||
|       await gu.enterCell('Bananas'); | ||||
| 
 | ||||
|       // Ensure all 3 changes are visible.
 | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(0, [1, 2, 3, 4, 5, 6]), | ||||
|         ['Oranges', 'Apples', '', 'Apples', 'Bananas', '']); | ||||
| 
 | ||||
|       // Check that the filter menu looks as expected.
 | ||||
|       menu = await gu.openColumnMenu('A', 'Filter'); | ||||
|       assert.deepEqual(await gu.getFilterMenuState(), [ | ||||
|         { checked: false, value: '', count: 1}, | ||||
|         { checked: true, value: 'Apples', count: 2}, | ||||
|         { checked: false, value: 'Bananas', count: 3}, | ||||
|         { checked: false, value: 'Oranges', count: 2} | ||||
|       ]); | ||||
| 
 | ||||
|       // Apply the filter to make it only-Apples again.
 | ||||
|       await menu.find('.test-filter-menu-apply-btn').click(); | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(0, [1, 2, 3]), | ||||
|         ['Apples', 'Apples', '']); | ||||
| 
 | ||||
|       // Reset the filter
 | ||||
|       menu = await gu.openColumnMenu('A', 'Filter'); | ||||
|       assert.deepEqual( | ||||
|         await driver.findAll('.test-filter-menu-bulk-action:not([class*=-disabled])', (e) => e.getText()), | ||||
|         ['All', 'None']); | ||||
|       await driver.findContent('.test-filter-menu-bulk-action', /All/).click(); | ||||
|       await menu.find('.test-filter-menu-apply-btn').click(); | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(0, [1, 2, 3, 4, 5, 6, 7, 8]), | ||||
|         ['Oranges', 'Oranges', 'Bananas', 'Apples', 'Bananas', '', 'Apples', 'Bananas']); | ||||
| 
 | ||||
|       // Restore changes of this test case.
 | ||||
|       await gu.undo(3); | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(0, [1, 2, 3, 4, 5, 6]), | ||||
|         ['Apples', 'Oranges', 'Bananas', 'Apples', 'Bananas', 'Apples']); | ||||
|     }); | ||||
| 
 | ||||
|     it('should display new/updated rows even when filtered, but refilter on menu changes', async () => { | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(0, [1, 2, 3, 4, 5, 6]), | ||||
|         ['Apples', 'Oranges', 'Bananas', 'Apples', 'Bananas', 'Apples']); | ||||
| 
 | ||||
|       let menu = await gu.openColumnMenu('A', 'Filter'); | ||||
| 
 | ||||
|       await menu.findContent('label', /Apples/).click(); | ||||
|       await driver.find('.test-filter-menu-apply-btn').click(); | ||||
| 
 | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(0, [1, 2, 3]), | ||||
|         ['Oranges', 'Bananas', 'Bananas']); | ||||
| 
 | ||||
|       // Update Oranges to Apples and make sure it's not filtered out
 | ||||
|       await (await gu.getCell(0, 1)).click(); | ||||
|       await gu.enterCell('Apples'); | ||||
| 
 | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(0, [1, 2, 3]), | ||||
|         ['Apples', 'Bananas', 'Bananas']); | ||||
| 
 | ||||
|       // Set back to Oranges and make sure it stays
 | ||||
|       await driver.sendKeys(Key.UP); | ||||
|       await gu.enterCell('Oranges'); | ||||
| 
 | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(0, [1, 2, 3]), | ||||
|         ['Oranges', 'Bananas', 'Bananas']); | ||||
| 
 | ||||
|       // Enter two new rows and make sure they're also not filtered out
 | ||||
|       await driver.find('.gridview_row .record-add .field').click(); | ||||
|       await gu.enterCell('Apples'); | ||||
|       await gu.enterCell('Bananas'); | ||||
| 
 | ||||
|       // Enter a new row using a keyboard shortcut.
 | ||||
|       await driver.find('body').sendKeys(Key.chord(await gu.modKey(), Key.ENTER)); | ||||
|       await gu.waitForServer(); | ||||
| 
 | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(0, [1, 2, 3, 4, 5, 6]), | ||||
|         ['Oranges', 'Bananas', 'Bananas', 'Apples', 'Bananas', '']); | ||||
| 
 | ||||
|       menu = await gu.openColumnMenu('A', 'Filter'); | ||||
|       assert.deepEqual(await gu.getFilterMenuState(), [ | ||||
|         { checked: true, value: '', count: 1}, | ||||
|         { checked: false, value: 'Apples', count: 4}, | ||||
|         { checked: true, value: 'Bananas', count: 3}, | ||||
|         { checked: true, value: 'Oranges', count: 1} | ||||
|       ]); | ||||
| 
 | ||||
|       await menu.findContent('label', /Apples/).click(); | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(0, [1, 2, 3, 4, 5, 6, 7, 8]), | ||||
|         ['Apples', 'Oranges', 'Bananas', 'Apples', 'Bananas', 'Apples', 'Apples', 'Bananas']); | ||||
|       await menu.findContent('label', /Apples/).click(); | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(0, [1, 2, 3, 4]), | ||||
|         ['Oranges', 'Bananas', 'Bananas', 'Bananas']); | ||||
|       await driver.sendKeys(Key.ESCAPE); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('Type tests', function() { | ||||
| 
 | ||||
|     before(async function() { | ||||
|       const session = await gu.session().teamSite.login(); | ||||
|       await session.tempDoc(cleanup, 'FilterTest.grist'); | ||||
|     }); | ||||
| 
 | ||||
|     it('should properly filter strings', async () => { | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(0, [1, 2, 3, 4, 5, 6, 7, 8]), | ||||
|         ['Foo', 'Bar', '1', '2.0', '2016-01-01', '5+6', '', '']); | ||||
| 
 | ||||
|       const menu = await gu.openColumnMenu('Text', 'Filter'); | ||||
|       assert.deepEqual(await gu.getFilterMenuState(), [ | ||||
|         { checked: true, value: '', count: 1}, | ||||
|         { checked: true, value: '1', count: 1}, | ||||
|         { checked: true, value: '2.0', count: 1}, | ||||
|         { checked: true, value: '5+6', count: 1}, | ||||
|         { checked: true, value: '2016-01-01', count: 1}, | ||||
|         { checked: true, value: 'Bar', count: 1}, | ||||
|         { checked: true, value: 'Foo', count: 1} | ||||
|       ]); | ||||
|       await menu.findContent('label', /^$/).click(); | ||||
|       await menu.findContent('label', /Bar/).click(); | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(0, [1, 2, 3, 4, 5, 6, 7]), | ||||
|         ['Foo', '1', '2.0', '2016-01-01', '5+6', '', undefined]); | ||||
|       await menu.find('.test-filter-menu-cancel-btn').click(); | ||||
|     }); | ||||
| 
 | ||||
| 
 | ||||
|     it('should properly filter numbers', async () => { | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(1, [1, 2, 3, 4, 5, 6, 7, 8]), | ||||
|         ['5.00', '6.00', '7.00', '-1.00', 'foo', '0.00', '', '']); | ||||
| 
 | ||||
|       const menu = await gu.openColumnMenu('Number', 'Filter'); | ||||
|       assert.deepEqual(await gu.getFilterMenuState(), [ | ||||
|         { checked: true, value: '', count: 1}, | ||||
|         { checked: true, value: 'foo', count: 1}, | ||||
|         { checked: true, value: '-1.00', count: 1}, | ||||
|         { checked: true, value: '0.00', count: 1}, | ||||
|         { checked: true, value: '5.00', count: 1}, | ||||
|         { checked: true, value: '6.00', count: 1}, | ||||
|         { checked: true, value: '7.00', count: 1}, | ||||
|       ]); | ||||
|       await menu.findContent('label', /^$/).click(); | ||||
|       await menu.findContent('label', /7/).click(); | ||||
|       await menu.findContent('label', /foo/).click(); | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(1, [1, 2, 3, 4, 5, 6]), | ||||
|         ['5.00', '6.00', '-1.00', '0.00', '', undefined]); | ||||
|       await menu.find('.test-filter-menu-cancel-btn').click(); | ||||
|     }); | ||||
| 
 | ||||
|     it('should properly filter dates', async () => { | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(2, [1, 2, 3, 4, 5, 6, 7, 8]), | ||||
|         ['2019-06-03', '2019-06-07', '2019-06-05', 'bar', '2019-06-123', '0', '', '']); | ||||
| 
 | ||||
|       const menu = await gu.openColumnMenu('Date', 'Filter'); | ||||
|       assert.deepEqual(await gu.getFilterMenuState(), [ | ||||
|         { checked: true, value: '', count: 1}, | ||||
|         { checked: true, value: '2019-06-123', count: 1}, | ||||
|         { checked: true, value: 'bar', count: 1}, | ||||
|         { checked: true, value: '0', count: 1}, | ||||
|         { checked: true, value: '2019-06-03', count: 1}, | ||||
|         { checked: true, value: '2019-06-05', count: 1}, | ||||
|         { checked: true, value: '2019-06-07', count: 1}, | ||||
|       ]); | ||||
|       await menu.findContent('label', /^$/).click(); | ||||
|       await menu.findContent('label', /2019-06-05/).click(); | ||||
|       await menu.findContent('label', /bar/).click(); | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(2, [1, 2, 3, 4, 5, 6]), | ||||
|         ['2019-06-03', '2019-06-07', '2019-06-123', '0', '', undefined]); | ||||
|       await menu.find('.test-filter-menu-cancel-btn').click(); | ||||
|     }); | ||||
| 
 | ||||
|     it('should properly search through list of date to filter', async () => { | ||||
|       const menu = await gu.openColumnMenu('Date', 'Filter'); | ||||
|       assert.lengthOf(await gu.getFilterMenuState(), 7); | ||||
|       await driver.sendKeys('07'); | ||||
|       assert.deepEqual(await gu.getFilterMenuState(), [ | ||||
|         { checked: true, value: '2019-06-07', count: 1} | ||||
|       ]); | ||||
|       assert.deepEqual( | ||||
|         await menu.findAll('.test-filter-menu-list label', (e) => e.getText()), | ||||
|         ['2019-06-07'] | ||||
|       ); | ||||
|       await menu.findContent('.test-filter-menu-bulk-action', /All Shown/).click(); | ||||
|       assert.deepEqual( | ||||
|         await gu.getVisibleGridCells(2, [1, 2]), | ||||
|         ['2019-06-07', ''] | ||||
|       ); | ||||
|       await menu.find('.test-filter-menu-cancel-btn').click(); | ||||
|     }); | ||||
| 
 | ||||
|     it('should properly filter formulas', async () => { | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(3, [1, 2, 3, 4, 5, 6, 7, 8]), | ||||
|         ['25', '36', '49', '1', '#TypeError', '0', '#TypeError', '']); | ||||
| 
 | ||||
|       const menu = await gu.openColumnMenu('Formula', 'Filter'); | ||||
|       assert.deepEqual(await gu.getFilterMenuState(), [ | ||||
|         { checked: true, value: '#TypeError', count: 2}, | ||||
|         { checked: true, value: '0', count: 1}, | ||||
|         { checked: true, value: '1', count: 1}, | ||||
|         { checked: true, value: '25', count: 1}, | ||||
|         { checked: true, value: '36', count: 1}, | ||||
|         { checked: true, value: '49', count: 1}, | ||||
|       ]); | ||||
| 
 | ||||
|       await menu.findContent('label', /0/).click(); | ||||
|       await menu.findContent('label', /#TypeError/).click(); | ||||
|       await menu.findContent('label', /25/).click(); | ||||
| 
 | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(3, [1, 2, 3, 4, 5]), | ||||
|         ['36', '49', '1', '', undefined]); | ||||
|       await menu.find('.test-filter-menu-cancel-btn').click(); | ||||
|     }); | ||||
| 
 | ||||
|     it('should properly filter references', async () => { | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(4, [1, 2, 3, 4, 5, 6, 7, 8]), | ||||
|         ['alice', 'carol', 'bob', 'denis', '0', 'denis', '', '']); | ||||
| 
 | ||||
|       const menu = await gu.openColumnMenu('Reference', 'Filter'); | ||||
|       assert.deepEqual(await gu.getFilterMenuState(), [ | ||||
|         { checked: true, value: '', count: 1}, | ||||
|         { checked: true, value: '#Invalid Ref: 0', count: 1}, | ||||
|         { checked: true, value: '#Invalid Ref: denis', count: 2}, | ||||
|         { checked: true, value: 'alice', count: 1}, | ||||
|         { checked: true, value: 'bob', count: 1}, | ||||
|         { checked: true, value: 'carol', count: 1}, | ||||
|       ]); | ||||
| 
 | ||||
|       await menu.findContent('label', /^$/).click(); | ||||
|       await menu.findContent('label', /#Invalid Ref: denis/).click(); | ||||
|       await menu.findContent('label', /bob/).click(); | ||||
| 
 | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(4, [1, 2, 3, 4, 5]), | ||||
|         ['alice', 'carol', '0', '', undefined]); | ||||
|       await menu.find('.test-filter-menu-cancel-btn').click(); | ||||
|     }); | ||||
| 
 | ||||
|     it('should properly filter choice lists', async () => { | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(5, [1, 2, 3, 4, 5, 6, 7, 8]), | ||||
|         ['Foo\nBar\nBaz', 'Foo\nBar', 'Foo', 'InvalidChoice', 'Baz\nBaz\nBaz', 'Bar\nBaz', '', '']); | ||||
| 
 | ||||
|       const menu = await gu.openColumnMenu('ChoiceList', 'Filter'); | ||||
|       assert.deepEqual(await gu.getFilterMenuState(), [ | ||||
|         { checked: true, value: '', count: 1}, | ||||
|         { checked: true, value: 'Bar', count: 3}, | ||||
|         { checked: true, value: 'Baz', count: 5}, | ||||
|         { checked: true, value: 'Foo', count: 3}, | ||||
|         { checked: true, value: 'InvalidChoice', count: 1}, | ||||
|       ]); | ||||
| 
 | ||||
|       // Check that all the choices are rendered in the right colors.
 | ||||
|       const choiceColors = await menu.findAll( | ||||
|         'label .test-filter-menu-choice-token', | ||||
|         async (c) => [await c.getCssValue('background-color'), await c.getCssValue('color')] | ||||
|       ); | ||||
| 
 | ||||
|       assert.deepEqual( | ||||
|         choiceColors, | ||||
|         [ | ||||
|           [ 'rgba(254, 204, 129, 1)', 'rgba(0, 0, 0, 1)' ], | ||||
|           [ 'rgba(53, 253, 49, 1)', 'rgba(0, 0, 0, 1)' ], | ||||
|           [ 'rgba(204, 254, 254, 1)', 'rgba(0, 0, 0, 1)' ], | ||||
|           [ 'rgba(255, 255, 255, 1)', 'rgba(0, 0, 0, 1)' ] | ||||
|         ] | ||||
|       ); | ||||
| 
 | ||||
|       // Check that Foo is rendered with font options.
 | ||||
|       const boldFonts = await menu.findAll( | ||||
|         'label .test-filter-menu-choice-token.font-italic.font-bold', | ||||
|         (c) => c.getText() | ||||
|       ); | ||||
| 
 | ||||
|       assert.deepEqual(boldFonts, ['Foo']); | ||||
| 
 | ||||
|       await menu.findContent('label', /^$/).click(); | ||||
|       await menu.findContent('label', /Bar/).click(); | ||||
|       await menu.findContent('label', /Baz/).click(); | ||||
| 
 | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(5, [1, 2, 3, 4, 5]), | ||||
|         ['Foo\nBar\nBaz', 'Foo\nBar', 'Foo', 'InvalidChoice', '']); | ||||
|       await menu.find('.test-filter-menu-cancel-btn').click(); | ||||
|     }); | ||||
| 
 | ||||
|     it('should properly filter errors in choice lists', async () => { | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(6, [1, 2, 3, 4, 5, 6, 7, 8]), | ||||
|         ['25.0', '36.0', '49.0', '1.0', '#TypeError', '', '#TypeError', '']); | ||||
| 
 | ||||
|       await gu.scrollIntoView(gu.getColumnHeader('ChoiceListErrors')); | ||||
|       const menu = await gu.openColumnMenu('ChoiceListErrors', 'Filter'); | ||||
|       assert.deepEqual(await gu.getFilterMenuState(), [ | ||||
|         { checked: true, value: '', count: 1}, | ||||
|         { checked: true, value: '#TypeError', count: 2}, | ||||
|         { checked: true, value: '1.0', count: 1}, | ||||
|         { checked: true, value: '25.0', count: 1}, | ||||
|         { checked: true, value: '36.0', count: 1}, | ||||
|         { checked: true, value: '49.0', count: 1}, | ||||
|         { checked: true, value: 'A', count: 0}, | ||||
|         { checked: true, value: 'B', count: 0}, | ||||
|         { checked: true, value: 'C', count: 0}, | ||||
|         { checked: true, value: 'D', count: 0}, | ||||
|       ]); | ||||
| 
 | ||||
|       await menu.findContent('label', /^$/).click(); | ||||
|       await menu.findContent('label', /#TypeError/).click(); | ||||
|       await menu.findContent('label', /25\.0/).click(); | ||||
|       await menu.findContent('label', /36\.0/).click(); | ||||
|       await menu.findContent('label', /49\.0/).click(); | ||||
| 
 | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(6, [1, 2]), | ||||
|         ['1.0', '']); | ||||
|       await menu.find('.test-filter-menu-cancel-btn').click(); | ||||
|     }); | ||||
| 
 | ||||
|     it('should properly filter choices', async () => { | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(7, [1, 2, 3, 4, 5, 6, 7, 8]), | ||||
|         ['Red', 'Orange', 'Yellow', 'InvalidChoice', '', 'Red', '', '']); | ||||
| 
 | ||||
|       const menu = await gu.openColumnMenu('Choice', 'Filter'); | ||||
|       assert.deepEqual(await gu.getFilterMenuState(), [ | ||||
|         { checked: true, value: '', count: 2}, | ||||
|         { checked: true, value: 'InvalidChoice', count: 1}, | ||||
|         { checked: true, value: 'Orange', count: 1}, | ||||
|         { checked: true, value: 'Red', count: 2}, | ||||
|         { checked: true, value: 'Yellow', count: 1}, | ||||
|       ]); | ||||
| 
 | ||||
|       // Check that all the choices are rendered in the right colors.
 | ||||
|       const choiceColors = await menu.findAll( | ||||
|         'label .test-filter-menu-choice-token', | ||||
|         async (c) => [await c.getCssValue('background-color'), await c.getCssValue('color')] | ||||
|       ); | ||||
| 
 | ||||
|       assert.deepEqual( | ||||
|         choiceColors, | ||||
|         [ | ||||
|           [ 'rgba(255, 255, 255, 1)', 'rgba(0, 0, 0, 1)' ], | ||||
|           [ 'rgba(254, 204, 129, 1)', 'rgba(0, 0, 0, 1)' ], | ||||
|           [ 'rgba(252, 54, 59, 1)', 'rgba(255, 255, 255, 1)' ], | ||||
|           [ 'rgba(255, 250, 205, 1)', 'rgba(0, 0, 0, 1)' ] | ||||
|         ] | ||||
|       ); | ||||
| 
 | ||||
|       // Check that Red is rendered with font options.
 | ||||
|       const withFonts = await menu.findAll( | ||||
|         'label .test-filter-menu-choice-token.font-underline.font-strikethrough', | ||||
|         (c) => c.getText() | ||||
|       ); | ||||
| 
 | ||||
|       assert.deepEqual(withFonts, ['Red']); | ||||
| 
 | ||||
|       await menu.findContent('label', /InvalidChoice/).click(); | ||||
|       await menu.findContent('label', /Orange/).click(); | ||||
|       await menu.findContent('label', /Yellow/).click(); | ||||
| 
 | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(7, [1, 2, 3, 4, 5]), | ||||
|         ['Red', '', 'Red', '', '']); | ||||
|       await menu.find('.test-filter-menu-cancel-btn').click(); | ||||
|     }); | ||||
| 
 | ||||
|     it('should properly filter reference lists', async () => { | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(8, [1, 2, 3, 4, 5, 6, 7, 8]), | ||||
|         ['alice\ncarol', 'bob', 'carol\nbob\nalice', '[u\'denis\']', '[u\'0\']', '[u\'denis\', u\'edward\']', '', '']); | ||||
| 
 | ||||
|       const menu = await gu.openColumnMenu('ReferenceList', 'Filter'); | ||||
|       assert.deepEqual(await gu.getFilterMenuState(), [ | ||||
|         { checked: true, value: '', count: 1 }, | ||||
|         { checked: true, value: '#Invalid RefList: [u\'0\']', count: 1 }, | ||||
|         { | ||||
|           checked: true, | ||||
|           value: '#Invalid RefList: [u\'denis\', u\'edward\']', | ||||
|           count: 1 | ||||
|         }, | ||||
|         { | ||||
|           checked: true, | ||||
|           value: '#Invalid RefList: [u\'denis\']', | ||||
|           count: 1 | ||||
|         }, | ||||
|         { checked: true, value: 'alice', count: 2 }, | ||||
|         { checked: true, value: 'bob', count: 2 }, | ||||
|         { checked: true, value: 'carol', count: 2 } | ||||
|       ]); | ||||
| 
 | ||||
|       await menu.findContent('label', /^$/).click(); | ||||
|       await menu.findContent('label', /bob/).click(); | ||||
|       await menu.findContent('label', /#Invalid RefList: \[u'0'\]/).click(); | ||||
| 
 | ||||
|       assert.deepEqual(await gu.getVisibleGridCells(8, [1, 2, 3, 4, 5]), | ||||
|         ['alice\ncarol', 'carol\nbob\nalice', '[u\'denis\']', '[u\'denis\', u\'edward\']', '']); | ||||
|       await menu.find('.test-filter-menu-cancel-btn').click(); | ||||
|     }); | ||||
| 
 | ||||
|     it('should reflect the section show column setting in the filter menu', async () => { | ||||
|       // Scroll col 3 into view to make sure col 4 is clickable
 | ||||
|       await gu.scrollIntoView(gu.getCell(3, 1)); | ||||
| 
 | ||||
|       // Change the show column setting of the Reference column to 'color'.
 | ||||
|       await gu.getCell(4, 1).click(); | ||||
|       await gu.toggleSidePanel('right', 'open'); | ||||
|       await driver.find('.test-right-tab-field').click(); | ||||
|       await gu.setRefShowColumn('color'); | ||||
| 
 | ||||
|       // Open the filter menu for Reference, and check that the values are now from 'color'.
 | ||||
|       const menu = await gu.openColumnMenu('Reference', 'Filter'); | ||||
|       assert.deepEqual(await gu.getFilterMenuState(), [ | ||||
|         { checked: true, value: '', count: 1 }, | ||||
|         { checked: true, value: '#Invalid Ref: 0', count: 1 }, | ||||
|         { checked: true, value: '#Invalid Ref: denis', count: 2 }, | ||||
|         { checked: true, value: 'blue', count: 1 }, | ||||
|         { checked: true, value: 'green', count: 1 }, | ||||
|         { checked: true, value: 'red', count: 1 } | ||||
|       ]); | ||||
| 
 | ||||
|       await menu.find('.test-filter-menu-cancel-btn').click(); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user