mirror of
				https://github.com/gristlabs/grist-core.git
				synced 2025-06-13 20:53:59 +00:00 
			
		
		
		
	Moving 3 ACinput tests to grist core
This commit is contained in:
		
							parent
							
								
									62cf6edfc5
								
							
						
					
					
						commit
						9da6fec7ad
					
				
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -4,6 +4,9 @@
 | 
			
		||||
/static/*.bundle.js.map
 | 
			
		||||
/static/bundle.css
 | 
			
		||||
/static/browser-check.js
 | 
			
		||||
/static/*.bundle.js.*.txt
 | 
			
		||||
/grist-sessions.db
 | 
			
		||||
/landing.db
 | 
			
		||||
 | 
			
		||||
# Build helper files.
 | 
			
		||||
/.build*
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								test/fixtures/docs/Ref-AC-Test.grist
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								test/fixtures/docs/Ref-AC-Test.grist
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								test/fixtures/docs/Ref-List-AC-Test.grist
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								test/fixtures/docs/Ref-List-AC-Test.grist
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										961
									
								
								test/nbrowser/ChoiceList.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										961
									
								
								test/nbrowser/ChoiceList.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,961 @@
 | 
			
		||||
import {assert, driver, Key, stackWrapFunc, WebElement} from 'mocha-webdriver';
 | 
			
		||||
import * as gu from 'test/nbrowser/gristUtils';
 | 
			
		||||
import {setupTestSuite} from 'test/nbrowser/testUtils';
 | 
			
		||||
 | 
			
		||||
const normalFont = { bold: false, underline: false, italic: false, strikethrough: false};
 | 
			
		||||
const bold = true;
 | 
			
		||||
const underline = true;
 | 
			
		||||
const italic = true;
 | 
			
		||||
const strikethrough = true;
 | 
			
		||||
 | 
			
		||||
function getEditorTokens() {
 | 
			
		||||
  return driver.findAll('.cell_editor .test-tokenfield .test-tokenfield-token', el => el.getText());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getEditorTokenStyles() {
 | 
			
		||||
  return driver.findAll(
 | 
			
		||||
    '.cell_editor .test-tokenfield .test-tokenfield-token',
 | 
			
		||||
    async el => {
 | 
			
		||||
      const classList = await el.getAttribute("class");
 | 
			
		||||
      return {
 | 
			
		||||
        fillColor: await el.getCssValue('background-color'),
 | 
			
		||||
        textColor: await el.getCssValue('color'),
 | 
			
		||||
        boxShadow: await el.getCssValue('box-shadow'),
 | 
			
		||||
        bold: classList.includes("font-bold"),
 | 
			
		||||
        italic: classList.includes("font-italic"),
 | 
			
		||||
        underline: classList.includes("font-underline"),
 | 
			
		||||
        strikethrough: classList.includes("font-strikethrough"),
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getCellTokens(cell: WebElement) {
 | 
			
		||||
  return cell.getText();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getCellTokenStyles(cell: WebElement) {
 | 
			
		||||
  return cell.findAll(
 | 
			
		||||
    '.test-choice-list-cell-token',
 | 
			
		||||
    async el => {
 | 
			
		||||
      const classList = await el.getAttribute("class");
 | 
			
		||||
      return {
 | 
			
		||||
        fillColor: await el.getCssValue('background-color'),
 | 
			
		||||
        textColor: await el.getCssValue('color'),
 | 
			
		||||
        boxShadow: await el.getCssValue('box-shadow'),
 | 
			
		||||
        bold: classList.includes("font-bold"),
 | 
			
		||||
        italic: classList.includes("font-italic"),
 | 
			
		||||
        underline: classList.includes("font-underline"),
 | 
			
		||||
        strikethrough: classList.includes("font-strikethrough"),
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getChoiceLabels() {
 | 
			
		||||
  return driver.findAll('.test-right-panel .test-choice-list-entry-label', el => el.getText());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getChoiceColors() {
 | 
			
		||||
  return driver.findAll(
 | 
			
		||||
    '.test-right-panel .test-choice-list-entry-color',
 | 
			
		||||
    el => el.getCssValue('background-color')
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getEditModeChoiceLabels() {
 | 
			
		||||
  return driver.findAll('.test-right-panel .test-tokenfield-token input', el => el.value());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getEditModeFillColors() {
 | 
			
		||||
  return driver.findAll(
 | 
			
		||||
    '.test-right-panel .test-tokenfield-token .test-color-button',
 | 
			
		||||
    el => el.getCssValue('background-color')
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getEditModeTextColors() {
 | 
			
		||||
  return driver.findAll(
 | 
			
		||||
    '.test-right-panel .test-tokenfield-token .test-color-button',
 | 
			
		||||
    el => el.getCssValue('color')
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getEditModeFontOptions() {
 | 
			
		||||
  return driver.findAll(
 | 
			
		||||
    '.test-right-panel .test-tokenfield-token .test-color-button',
 | 
			
		||||
    async el => {
 | 
			
		||||
      const classes = await el.getAttribute("class");
 | 
			
		||||
      const options: any = {};
 | 
			
		||||
      if (classes.includes("font-bold")) {
 | 
			
		||||
        options['bold'] = true;
 | 
			
		||||
      }
 | 
			
		||||
      if (classes.includes("font-underline")) {
 | 
			
		||||
        options['underline'] = true;
 | 
			
		||||
      }
 | 
			
		||||
      if (classes.includes("font-italic")) {
 | 
			
		||||
        options['italic'] = true;
 | 
			
		||||
      }
 | 
			
		||||
      if (classes.includes("font-strikethrough")) {
 | 
			
		||||
        options['strikethrough'] = true;
 | 
			
		||||
      }
 | 
			
		||||
      return options;
 | 
			
		||||
    }
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getEditorTokensIsInvalid() {
 | 
			
		||||
  return driver.findAll('.cell_editor .test-tokenfield .test-tokenfield-token', el => el.matches('[class*=-invalid]'));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getEditorInput() {
 | 
			
		||||
  return driver.find('.cell_editor .test-tokenfield .test-tokenfield-input');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function editChoiceEntries() {
 | 
			
		||||
  await driver.find(".test-choice-list-entry").click();
 | 
			
		||||
  await gu.waitAppFocus(false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function renameEntry(from: string, to: string) {
 | 
			
		||||
  await clickEntry(from);
 | 
			
		||||
  await gu.sendKeys(to);
 | 
			
		||||
  await gu.sendKeys(Key.ENTER);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async function clickEntry(label: string) {
 | 
			
		||||
  const entry = await driver.findWait(`.test-choice-list-entry .test-token-label[value='${label}']`, 100);
 | 
			
		||||
  await entry.click();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function saveChoiceEntries() {
 | 
			
		||||
  await driver.find(".test-choice-list-entry-save").click();
 | 
			
		||||
  await gu.waitForServer();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
describe('ChoiceList', function() {
 | 
			
		||||
  this.timeout(20000);
 | 
			
		||||
  const cleanup = setupTestSuite();
 | 
			
		||||
 | 
			
		||||
  const WHITE_FILL = 'rgba(255, 255, 255, 1)';
 | 
			
		||||
  const UNSET_FILL = WHITE_FILL;
 | 
			
		||||
  const INVALID_FILL = WHITE_FILL;
 | 
			
		||||
  const DEFAULT_FILL = 'rgba(232, 232, 232, 1)';
 | 
			
		||||
  const GREEN_FILL = 'rgba(225, 254, 222, 1)';
 | 
			
		||||
  const DARK_GREEN_FILL = 'rgba(18, 110, 14, 1)';
 | 
			
		||||
  const BLUE_FILL = 'rgba(204, 254, 254, 1)';
 | 
			
		||||
  const BLACK_FILL = 'rgba(0, 0, 0, 1)';
 | 
			
		||||
  const BLACK_TEXT = 'rgba(0, 0, 0, 1)';
 | 
			
		||||
  const WHITE_TEXT = 'rgba(255, 255, 255, 1)';
 | 
			
		||||
  const APRICOT_FILL = 'rgba(254, 204, 129, 1)';
 | 
			
		||||
  const APRICOT_TEXT = 'rgba(70, 13, 129, 1)';
 | 
			
		||||
  const DEFAULT_TEXT = BLACK_TEXT;
 | 
			
		||||
  const INVALID_TEXT = BLACK_TEXT;
 | 
			
		||||
  const VALID_CHOICE = {
 | 
			
		||||
    boxShadow: 'none',
 | 
			
		||||
    ...normalFont,
 | 
			
		||||
  };
 | 
			
		||||
  const INVALID_CHOICE = {
 | 
			
		||||
    fillColor: INVALID_FILL,
 | 
			
		||||
    textColor: INVALID_TEXT,
 | 
			
		||||
    boxShadow: 'rgb(208, 2, 27) 0px 0px 0px 1px inset',
 | 
			
		||||
    ...normalFont,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  afterEach(() => gu.checkForErrors());
 | 
			
		||||
 | 
			
		||||
  it('should support basic editing', async () => {
 | 
			
		||||
    const mainSession = await gu.session().teamSite.login();
 | 
			
		||||
    const api = mainSession.createHomeApi();
 | 
			
		||||
    const docId = await mainSession.tempNewDoc(cleanup, 'FormulaCounts', {load: true});
 | 
			
		||||
 | 
			
		||||
    // Make a ChoiceList column and add some data.
 | 
			
		||||
    await api.applyUserActions(docId, [
 | 
			
		||||
      ['ModifyColumn', 'Table1', 'B', {
 | 
			
		||||
        type: 'ChoiceList',
 | 
			
		||||
        widgetOptions: JSON.stringify({
 | 
			
		||||
          choices: ['Green', 'Blue', 'Black'],
 | 
			
		||||
          choiceOptions: {
 | 
			
		||||
            'Green': {
 | 
			
		||||
              fillColor: '#e1fede',
 | 
			
		||||
              textColor: '#000000',
 | 
			
		||||
              fontBold: true
 | 
			
		||||
            },
 | 
			
		||||
            'Blue': {
 | 
			
		||||
              fillColor: '#ccfefe',
 | 
			
		||||
              textColor: '#000000'
 | 
			
		||||
            },
 | 
			
		||||
            'Black': {
 | 
			
		||||
              fillColor: '#000000',
 | 
			
		||||
              textColor: '#ffffff'
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      }],
 | 
			
		||||
      ['BulkAddRecord', 'Table1', [null, null, null], {}],
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    // Enter by typing into an empty cell: valid value, invalue value, then check the editor.
 | 
			
		||||
    await gu.getCell({rowNum: 1, col: 'B'}).click();
 | 
			
		||||
    await driver.sendKeys('Gre', Key.ENTER);
 | 
			
		||||
    await driver.sendKeys('fake', Key.ENTER);
 | 
			
		||||
    assert.deepEqual(await getEditorTokens(), ['Green', 'fake']);
 | 
			
		||||
    assert.deepEqual(await getEditorTokensIsInvalid(), [false, true]);
 | 
			
		||||
    assert.deepEqual(
 | 
			
		||||
      await getEditorTokenStyles(),
 | 
			
		||||
      [
 | 
			
		||||
        {fillColor: GREEN_FILL, textColor: BLACK_TEXT, ...VALID_CHOICE, bold},
 | 
			
		||||
        INVALID_CHOICE,
 | 
			
		||||
      ]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Escape to cancel; check nothing got saved.
 | 
			
		||||
    await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
    await gu.waitForServer();
 | 
			
		||||
    assert.equal(await driver.find('.cell_editor').isPresent(), false);
 | 
			
		||||
    assert.equal(await gu.getCell({rowNum: 1, col: 'B'}).getText(), '');
 | 
			
		||||
 | 
			
		||||
    // Type invalid value, then select from dropdown valid
 | 
			
		||||
    await gu.getCell({rowNum: 1, col: 'B'}).click();
 | 
			
		||||
    await driver.sendKeys('fake', Key.ENTER);
 | 
			
		||||
    await getEditorInput().click();
 | 
			
		||||
    const blueChoice = await driver.findContent('.test-autocomplete li', /Blue/);
 | 
			
		||||
    assert.equal(
 | 
			
		||||
      await blueChoice.find('.test-choice-list-editor-item-label').getCssValue('background-color'),
 | 
			
		||||
      BLUE_FILL
 | 
			
		||||
    );
 | 
			
		||||
    assert.equal(
 | 
			
		||||
      await blueChoice.find('.test-choice-list-editor-item-label').getCssValue('color'),
 | 
			
		||||
      BLACK_TEXT
 | 
			
		||||
    );
 | 
			
		||||
    await blueChoice.click();
 | 
			
		||||
 | 
			
		||||
    // Type another valid, check what's in editor
 | 
			
		||||
    await driver.sendKeys('black', Key.ENTER);
 | 
			
		||||
    assert.deepEqual(await getEditorTokens(), ['fake', 'Blue', 'Black']);
 | 
			
		||||
    assert.deepEqual(await getEditorTokensIsInvalid(), [true, false, false]);
 | 
			
		||||
    assert.deepEqual(
 | 
			
		||||
      await getEditorTokenStyles(),
 | 
			
		||||
      [
 | 
			
		||||
        INVALID_CHOICE,
 | 
			
		||||
        {fillColor: BLUE_FILL, textColor: BLACK_TEXT, ...VALID_CHOICE},
 | 
			
		||||
        {fillColor: BLACK_FILL, textColor: WHITE_TEXT, ...VALID_CHOICE}
 | 
			
		||||
      ]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Enter to save; check values got saved.
 | 
			
		||||
    await driver.sendKeys(Key.ENTER);
 | 
			
		||||
    await gu.waitForServer();
 | 
			
		||||
    assert.equal(await driver.find('.cell_editor').isPresent(), false);
 | 
			
		||||
    assert.equal(await getCellTokens(await gu.getCell({rowNum: 1, col: 'B'})), 'fake\nBlue\nBlack');
 | 
			
		||||
    assert.deepEqual(
 | 
			
		||||
      await getCellTokenStyles(await gu.getCell({rowNum: 1, col: 'B'})),
 | 
			
		||||
      [
 | 
			
		||||
        INVALID_CHOICE,
 | 
			
		||||
        {fillColor: BLUE_FILL, textColor: BLACK_TEXT, ...VALID_CHOICE},
 | 
			
		||||
        {fillColor: BLACK_FILL, textColor: WHITE_TEXT, ...VALID_CHOICE}
 | 
			
		||||
      ]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Enter to edit. Enter token, remove two tokens, with a key and with an x-click.
 | 
			
		||||
    await gu.getCell({rowNum: 1, col: 'B'}).click();
 | 
			
		||||
    await driver.sendKeys(Key.ENTER);
 | 
			
		||||
    assert.deepEqual(await getEditorTokens(), ['fake', 'Blue', 'Black']);
 | 
			
		||||
    await driver.sendKeys('Gre', Key.TAB);
 | 
			
		||||
    assert.deepEqual(await getEditorTokens(), ['fake', 'Blue', 'Black', 'Green']);
 | 
			
		||||
    await driver.sendKeys(Key.LEFT, Key.LEFT, Key.BACK_SPACE);
 | 
			
		||||
    assert.deepEqual(await getEditorTokens(), ['fake', 'Blue', 'Green']);
 | 
			
		||||
    const tok1 = driver.findContent('.cell_editor .test-tokenfield .test-tokenfield-token', /fake/);
 | 
			
		||||
    await tok1.mouseMove();
 | 
			
		||||
    await tok1.find('.test-tokenfield-delete').click();
 | 
			
		||||
    assert.deepEqual(await getEditorTokens(), ['Blue', 'Green']);
 | 
			
		||||
 | 
			
		||||
    // Enter to save; check values got saved.
 | 
			
		||||
    await driver.sendKeys(Key.ENTER);
 | 
			
		||||
    await gu.waitForServer();
 | 
			
		||||
    assert.equal(await driver.find('.cell_editor').isPresent(), false);
 | 
			
		||||
    assert.equal(await getCellTokens(gu.getCell({rowNum: 1, col: 'B'})), 'Blue\nGreen');
 | 
			
		||||
 | 
			
		||||
    // Start typing to replace content with a token; check values.
 | 
			
		||||
    await gu.getCell({rowNum: 1, col: 'B'}).click();
 | 
			
		||||
    await driver.sendKeys('foo');
 | 
			
		||||
    assert.deepEqual(await getEditorTokens(), []);
 | 
			
		||||
    assert.equal(await getEditorInput().value(), 'foo');
 | 
			
		||||
    await driver.sendKeys(Key.TAB);
 | 
			
		||||
    assert.deepEqual(await getEditorTokens(), ['foo']);
 | 
			
		||||
 | 
			
		||||
    // Escape to cancel; check nothing got saved.
 | 
			
		||||
    await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
    await gu.waitForServer();
 | 
			
		||||
    assert.equal(await driver.find('.cell_editor').isPresent(), false);
 | 
			
		||||
    assert.equal(await gu.getCell({rowNum: 1, col: 'B'}).getText(), 'Blue\nGreen');
 | 
			
		||||
 | 
			
		||||
    // Double-click to open dropdown and select a token.
 | 
			
		||||
    await driver.withActions(a => a.doubleClick(gu.getCell({rowNum: 1, col: 'B'})));
 | 
			
		||||
    await driver.findContent('.test-autocomplete li', /Black/).click();
 | 
			
		||||
    assert.deepEqual(await getEditorTokens(), ['Blue', 'Green', 'Black']);
 | 
			
		||||
 | 
			
		||||
    // Click away to save: new token should be added.
 | 
			
		||||
    await gu.getCell({rowNum: 2, col: 'B'}).click();
 | 
			
		||||
    await gu.waitForServer();
 | 
			
		||||
    assert.equal(await driver.find('.cell_editor').isPresent(), false);
 | 
			
		||||
    assert.equal(await gu.getCell({rowNum: 1, col: 'B'}).getText(), 'Blue\nGreen\nBlack');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should be visible in formulas', async () => {
 | 
			
		||||
    // Add a formula that returns tokens reversed
 | 
			
		||||
    await gu.getCell({rowNum: 1, col: 'C'}).click();
 | 
			
		||||
    await gu.enterFormula('":".join($B)');
 | 
			
		||||
 | 
			
		||||
    // Check value
 | 
			
		||||
    assert.deepEqual(await gu.getVisibleGridCells({rowNums: [1, 2, 3], cols: ['B', 'C']}), [
 | 
			
		||||
      'Blue\nGreen\nBlack', 'Blue:Green:Black',
 | 
			
		||||
      '', '',
 | 
			
		||||
      '', '',
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    // Hit enter, click to delete a token, save.
 | 
			
		||||
    await gu.getCell({rowNum: 1, col: 'B'}).click();
 | 
			
		||||
    await driver.sendKeys(Key.ENTER);
 | 
			
		||||
    await driver.sendKeys(Key.BACK_SPACE);
 | 
			
		||||
    await driver.sendKeys(Key.ENTER);
 | 
			
		||||
    await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
    // Check formula got updated
 | 
			
		||||
    assert.deepEqual(await gu.getVisibleGridCells({rowNums: [1], cols: ['B', 'C']}), [
 | 
			
		||||
      'Blue\nGreen', 'Blue:Green',
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    // Type a couple new tokens.
 | 
			
		||||
    await gu.getCell({rowNum: 1, col: 'B'}).click();
 | 
			
		||||
    await driver.sendKeys(Key.ENTER);
 | 
			
		||||
    await driver.sendKeys('fake', Key.TAB, 'Bla', Key.TAB);
 | 
			
		||||
 | 
			
		||||
    // Enter to save; check formula got updated
 | 
			
		||||
    await driver.sendKeys(Key.ENTER);
 | 
			
		||||
    await gu.waitForServer();
 | 
			
		||||
    assert.deepEqual(await gu.getVisibleGridCells({rowNums: [1], cols: ['B', 'C']}), [
 | 
			
		||||
      'Blue\nGreen\nfake\nBlack', 'Blue:Green:fake:Black',
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    // Hit delete. ChoiceList cell and formula should clear.
 | 
			
		||||
    await gu.getCell({rowNum: 1, col: 'B'}).click();
 | 
			
		||||
    await driver.sendKeys(Key.DELETE);
 | 
			
		||||
    await gu.waitForServer();
 | 
			
		||||
    assert.deepEqual(await gu.getVisibleGridCells({rowNums: [1, 2, 3], cols: ['B', 'C']}), [
 | 
			
		||||
      '', '',
 | 
			
		||||
      '', '',
 | 
			
		||||
      '', '',
 | 
			
		||||
    ]);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should allow adding new values', async () => {
 | 
			
		||||
    // Check what choices are configured.
 | 
			
		||||
    await gu.toggleSidePanel('right', 'open');
 | 
			
		||||
    await driver.find('.test-right-tab-field').click();
 | 
			
		||||
    assert.deepEqual(await getChoiceLabels(), ['Green', 'Blue', 'Black']);
 | 
			
		||||
    assert.deepEqual(
 | 
			
		||||
      await getChoiceColors(),
 | 
			
		||||
      [GREEN_FILL, BLUE_FILL, BLACK_FILL]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Select a token from autocomplete
 | 
			
		||||
    const cell = gu.getCell({rowNum: 1, col: 'B'});
 | 
			
		||||
    assert.equal(await cell.getText(), '');
 | 
			
		||||
    await cell.click();
 | 
			
		||||
    await driver.sendKeys(Key.ENTER);
 | 
			
		||||
    await driver.findContent('.test-autocomplete li', /Green/).click();
 | 
			
		||||
    assert.deepEqual(await getEditorTokens(), ['Green']);
 | 
			
		||||
 | 
			
		||||
    // Type token that's not in autocomplete
 | 
			
		||||
    await driver.sendKeys("Orange");
 | 
			
		||||
 | 
			
		||||
    // Enter should add invalid token.
 | 
			
		||||
    await driver.sendKeys(Key.ENTER);
 | 
			
		||||
    assert.deepEqual(await getEditorTokens(), ['Green', 'Orange']);
 | 
			
		||||
    assert.deepEqual(await getEditorTokensIsInvalid(), [false, true]);
 | 
			
		||||
 | 
			
		||||
    // Type another token, and click the "+" button in autocomplete. New token should be valid.
 | 
			
		||||
    await driver.sendKeys("Apricot");
 | 
			
		||||
    const newChoice = await driver.find('.test-autocomplete .test-choice-list-editor-new-item');
 | 
			
		||||
    assert.equal(await newChoice.getText(), 'Apricot');
 | 
			
		||||
    assert.equal(
 | 
			
		||||
      await newChoice.find('.test-choice-list-editor-item-label').getCssValue('background-color'),
 | 
			
		||||
      DEFAULT_FILL
 | 
			
		||||
    );
 | 
			
		||||
    assert.equal(
 | 
			
		||||
      await newChoice.find('.test-choice-list-editor-item-label').getCssValue('color'),
 | 
			
		||||
      DEFAULT_TEXT
 | 
			
		||||
    );
 | 
			
		||||
    await driver.find('.test-autocomplete .test-choice-list-editor-new-item').click();
 | 
			
		||||
    assert.deepEqual(await getEditorTokens(), ['Green', 'Orange', 'Apricot']);
 | 
			
		||||
    assert.deepEqual(await getEditorTokensIsInvalid(), [false, true, false]);
 | 
			
		||||
    assert.deepEqual(
 | 
			
		||||
      await getEditorTokenStyles(),
 | 
			
		||||
      [
 | 
			
		||||
        {fillColor: GREEN_FILL, textColor: BLACK_TEXT, ...VALID_CHOICE, bold},
 | 
			
		||||
        INVALID_CHOICE,
 | 
			
		||||
        {fillColor: DEFAULT_FILL, textColor: DEFAULT_TEXT, ...VALID_CHOICE}
 | 
			
		||||
      ]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Save: check tokens
 | 
			
		||||
    await driver.sendKeys(Key.ENTER);
 | 
			
		||||
    await gu.waitForServer();
 | 
			
		||||
    assert.equal(await getCellTokens(gu.getCell({rowNum: 1, col: 'B'})), 'Green\nOrange\nApricot');
 | 
			
		||||
    assert.deepEqual(
 | 
			
		||||
      await getCellTokenStyles(gu.getCell({rowNum: 1, col: 'B'})),
 | 
			
		||||
      [
 | 
			
		||||
        {fillColor: GREEN_FILL, textColor: BLACK_TEXT, ...VALID_CHOICE, bold},
 | 
			
		||||
        INVALID_CHOICE,
 | 
			
		||||
        {fillColor: DEFAULT_FILL, textColor: DEFAULT_TEXT, ...VALID_CHOICE}
 | 
			
		||||
      ]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // New option should be listed in config.
 | 
			
		||||
    assert.deepEqual(await getChoiceLabels(), ['Green', 'Blue', 'Black', 'Apricot']);
 | 
			
		||||
    assert.deepEqual(
 | 
			
		||||
      await getChoiceColors(),
 | 
			
		||||
      [GREEN_FILL, BLUE_FILL, BLACK_FILL, UNSET_FILL]
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  const convertColumn = stackWrapFunc(async function(typeRe: RegExp) {
 | 
			
		||||
    await gu.setType(typeRe);
 | 
			
		||||
    await gu.waitForServer();
 | 
			
		||||
    await driver.findContent('.type_transform_prompt button', /Apply/).click();
 | 
			
		||||
    await gu.waitForServer();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should allow reasonable conversions between ChoiceList and other types', async function() {
 | 
			
		||||
    await gu.enterGridRows({rowNum: 1, col: 'A'},
 | 
			
		||||
      [['Hello'], ['World'], [' Foo,Bar;Baz!,']]);
 | 
			
		||||
    await testTextChoiceListConversions();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should allow ChoiceList conversions for column used in summary', async function() {
 | 
			
		||||
    // Add a widget with a summary on column A.
 | 
			
		||||
    await gu.addNewSection(/Table/, /Table1/, {summarize: [/^A$/]});
 | 
			
		||||
    await testTextChoiceListConversions();
 | 
			
		||||
    await gu.undo();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  async function testTextChoiceListConversions() {
 | 
			
		||||
    await gu.getCell({section: 'TABLE1', rowNum: 3, col: 'A'}).click();
 | 
			
		||||
 | 
			
		||||
    // Convert this text column to ChoiceList.
 | 
			
		||||
    await gu.toggleSidePanel('right', 'open');
 | 
			
		||||
    await driver.find('.test-right-tab-field').click();
 | 
			
		||||
    await convertColumn(/Choice List/);
 | 
			
		||||
 | 
			
		||||
    // Check that choices got populated.
 | 
			
		||||
    await driver.find('.test-right-tab-field').click();
 | 
			
		||||
    assert.deepEqual(await getChoiceLabels(), ['Hello', 'World', 'Foo', 'Bar;Baz!']);
 | 
			
		||||
    assert.deepEqual(
 | 
			
		||||
      await getChoiceColors(),
 | 
			
		||||
      [UNSET_FILL, UNSET_FILL, UNSET_FILL, UNSET_FILL]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Check that the result contains the right tags.
 | 
			
		||||
    assert.deepEqual(await gu.getVisibleGridCells({rowNums: [1, 2, 3], cols: ['A']}), [
 | 
			
		||||
      'Hello',
 | 
			
		||||
      'World',
 | 
			
		||||
      'Foo\nBar;Baz!'
 | 
			
		||||
    ]);
 | 
			
		||||
    await gu.checkForErrors();
 | 
			
		||||
 | 
			
		||||
    // Check that the result contains the right colors.
 | 
			
		||||
    for (const rowNum of [1, 2]) {
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await getCellTokenStyles(await gu.getCell({rowNum, col: 'A'})),
 | 
			
		||||
        [{fillColor: DEFAULT_FILL, textColor: DEFAULT_TEXT, ...VALID_CHOICE}]
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    assert.deepEqual(
 | 
			
		||||
      await getCellTokenStyles(await gu.getCell({rowNum: 3, col: 'A'})),
 | 
			
		||||
      [
 | 
			
		||||
        {fillColor: DEFAULT_FILL, textColor: DEFAULT_TEXT, ...VALID_CHOICE},
 | 
			
		||||
        {fillColor: DEFAULT_FILL, textColor: DEFAULT_TEXT, ...VALID_CHOICE},
 | 
			
		||||
      ]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Open a cell to see the actual tags.
 | 
			
		||||
    await gu.getCell({rowNum: 3, col: 'A'}).click();
 | 
			
		||||
    await driver.sendKeys(Key.ENTER);
 | 
			
		||||
    assert.deepEqual(await getEditorTokens(), ['Foo', 'Bar;Baz!']);
 | 
			
		||||
    assert.deepEqual(await getEditorTokensIsInvalid(), [false, false]);
 | 
			
		||||
    assert.deepEqual(
 | 
			
		||||
      await getEditorTokenStyles(),
 | 
			
		||||
      [
 | 
			
		||||
        {fillColor: DEFAULT_FILL, textColor: DEFAULT_TEXT, ...VALID_CHOICE},
 | 
			
		||||
        {fillColor: DEFAULT_FILL, textColor: DEFAULT_TEXT, ...VALID_CHOICE}
 | 
			
		||||
      ]
 | 
			
		||||
    );
 | 
			
		||||
    await driver.sendKeys("hooray", Key.TAB, Key.ENTER);
 | 
			
		||||
    await gu.waitForServer();
 | 
			
		||||
    await gu.checkForErrors();
 | 
			
		||||
 | 
			
		||||
    // Convert back to text.
 | 
			
		||||
    await convertColumn(/Text/);
 | 
			
		||||
 | 
			
		||||
    // Check that values turn into comma-separated values.
 | 
			
		||||
    assert.deepEqual(await gu.getVisibleGridCells({rowNums: [1, 2, 3], cols: ['A']}), [
 | 
			
		||||
      'Hello',
 | 
			
		||||
      'World',
 | 
			
		||||
      'Foo, Bar;Baz!, hooray'
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    // Undo the cell change and both conversions (back to ChoiceList, back to Text), and check
 | 
			
		||||
    // that UNDO also works correctly and without errors.
 | 
			
		||||
    await gu.undo(3);
 | 
			
		||||
    assert.deepEqual(await gu.getVisibleGridCells({rowNums: [1, 2, 3], cols: ['A']}), [
 | 
			
		||||
      'Hello',
 | 
			
		||||
      'World',
 | 
			
		||||
      ' Foo,Bar;Baz!,',   // That's the text originally entered into this Text cell.
 | 
			
		||||
    ]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  it('should keep choices when converting between Choice and ChoiceList', async function() {
 | 
			
		||||
    // Column B starts off as ChoiceList with the following choices.
 | 
			
		||||
    await gu.getCell({rowNum: 1, col: 'B'}).click();
 | 
			
		||||
    await driver.find('.test-right-tab-field').click();
 | 
			
		||||
    assert.deepEqual(await getChoiceLabels(), ['Green', 'Blue', 'Black', 'Apricot']);
 | 
			
		||||
 | 
			
		||||
    // Add some more values to this columm.
 | 
			
		||||
    await gu.getCell({rowNum: 2, col: 'B'}).click();
 | 
			
		||||
    await driver.sendKeys('Black', Key.ENTER, Key.ENTER);
 | 
			
		||||
    await gu.waitForServer();
 | 
			
		||||
    await driver.sendKeys('Green', Key.ENTER, Key.ENTER);
 | 
			
		||||
    await gu.waitForServer();
 | 
			
		||||
    assert.deepEqual(await gu.getVisibleGridCells({rowNums: [1, 2, 3], cols: ['B']}), [
 | 
			
		||||
      "Green\nOrange\nApricot",
 | 
			
		||||
      "Black",
 | 
			
		||||
      "Green",
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    // Convert to Choice. Configured Choices should stay the same.
 | 
			
		||||
    await convertColumn(/^Choice$/);
 | 
			
		||||
    assert.deepEqual(await getChoiceLabels(), ['Green', 'Blue', 'Black', 'Apricot']);
 | 
			
		||||
    assert.deepEqual(await getChoiceColors(), [GREEN_FILL, BLUE_FILL, BLACK_FILL, UNSET_FILL]);
 | 
			
		||||
 | 
			
		||||
    // Cells which contain multiple choices become CSVs.
 | 
			
		||||
    assert.deepEqual(await gu.getVisibleGridCells({rowNums: [1, 2, 3], cols: ['B']}), [
 | 
			
		||||
      "Green, Orange, Apricot",
 | 
			
		||||
      "Black",
 | 
			
		||||
      "Green",
 | 
			
		||||
    ]);
 | 
			
		||||
    const cell1 = gu.getCell('B', 1);
 | 
			
		||||
    assert.equal(await cell1.find('.field_clip').matches('.invalid'), false);
 | 
			
		||||
    assert.equal(await cell1.find('.test-choice-token').getCssValue('background-color'), INVALID_FILL);
 | 
			
		||||
    assert.equal(await cell1.find('.test-choice-token').getCssValue('color'), INVALID_TEXT);
 | 
			
		||||
    const cell2 = gu.getCell('B', 2);
 | 
			
		||||
    assert.equal(await cell2.find('.field_clip').matches('.invalid'), false);
 | 
			
		||||
    assert.equal(await cell2.find('.test-choice-token').getCssValue('background-color'), BLACK_FILL);
 | 
			
		||||
    assert.equal(await cell2.find('.test-choice-token').getCssValue('color'), WHITE_TEXT);
 | 
			
		||||
 | 
			
		||||
    // Convert back to ChoiceList. Choices should stay the same.
 | 
			
		||||
    await convertColumn(/Choice List/);
 | 
			
		||||
    assert.deepEqual(await getChoiceLabels(), ['Green', 'Blue', 'Black', 'Apricot']);
 | 
			
		||||
    assert.deepEqual(await getChoiceColors(), [GREEN_FILL, BLUE_FILL, BLACK_FILL, UNSET_FILL]);
 | 
			
		||||
 | 
			
		||||
    // Cell and editor data should be restored too.
 | 
			
		||||
    assert.deepEqual(await gu.getVisibleGridCells({rowNums: [1, 2, 3], cols: ['B']}), [
 | 
			
		||||
      "Green\nOrange\nApricot",
 | 
			
		||||
      "Black",
 | 
			
		||||
      "Green",
 | 
			
		||||
    ]);
 | 
			
		||||
    assert.deepEqual(
 | 
			
		||||
      await getCellTokenStyles(await gu.getCell({rowNum: 1, col: 'B'})),
 | 
			
		||||
      [
 | 
			
		||||
        {fillColor: GREEN_FILL, textColor: BLACK_TEXT, ...VALID_CHOICE, bold},
 | 
			
		||||
        INVALID_CHOICE,
 | 
			
		||||
        {fillColor: DEFAULT_FILL, textColor: DEFAULT_TEXT, ...VALID_CHOICE},
 | 
			
		||||
      ]
 | 
			
		||||
    );
 | 
			
		||||
    await gu.getCell({rowNum: 1, col: 'B'}).click();
 | 
			
		||||
    await driver.sendKeys(Key.ENTER);
 | 
			
		||||
    assert.deepEqual(await getEditorTokens(), ['Green', 'Orange', 'Apricot']);
 | 
			
		||||
    assert.deepEqual(await getEditorTokensIsInvalid(), [false, true, false]);
 | 
			
		||||
    assert.deepEqual(
 | 
			
		||||
      await getEditorTokenStyles(),
 | 
			
		||||
      [
 | 
			
		||||
        {fillColor: GREEN_FILL, textColor: BLACK_TEXT, ...VALID_CHOICE,  bold},
 | 
			
		||||
        INVALID_CHOICE,
 | 
			
		||||
        {fillColor: DEFAULT_FILL, textColor: DEFAULT_TEXT, ...VALID_CHOICE},
 | 
			
		||||
      ]
 | 
			
		||||
    );
 | 
			
		||||
    await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should allow setting choice style', async function() {
 | 
			
		||||
    // Open the choice editor.
 | 
			
		||||
    await driver.find('.test-choice-list-entry').click();
 | 
			
		||||
    await gu.waitAppFocus(false);
 | 
			
		||||
 | 
			
		||||
    // Change 'Apricot' to a light shade of orange with purple text.
 | 
			
		||||
    const [greenColorBtn, , , apricotColorBtn] = await driver
 | 
			
		||||
      .findAll('.test-tokenfield .test-color-button');
 | 
			
		||||
    await apricotColorBtn.click();
 | 
			
		||||
    await gu.setColor(driver.find('.test-fill-input'), 'rgb(254, 204, 129)');
 | 
			
		||||
    await gu.setColor(driver.find('.test-text-input'), 'rgb(70, 13, 129)');
 | 
			
		||||
    await gu.setFont('bold', true);
 | 
			
		||||
    await gu.setFont('italic', true);
 | 
			
		||||
    await driver.sendKeys(Key.ENTER);
 | 
			
		||||
 | 
			
		||||
    // Change 'Green' to a darker shade with white text.
 | 
			
		||||
    await greenColorBtn.click();
 | 
			
		||||
    await gu.setColor(driver.find('.test-fill-input'), 'rgb(18, 110, 14)');
 | 
			
		||||
    await gu.setColor(driver.find('.test-text-input'), 'rgb(255, 255, 255)');
 | 
			
		||||
    await gu.setFont('strikethrough', true);
 | 
			
		||||
    await gu.setFont('underline', true);
 | 
			
		||||
    await driver.sendKeys(Key.ENTER);
 | 
			
		||||
 | 
			
		||||
    // Check that the old colors are still being used in the grid
 | 
			
		||||
    assert.deepEqual(
 | 
			
		||||
      await getCellTokenStyles(await gu.getCell({rowNum: 1, col: 'B'})),
 | 
			
		||||
      [
 | 
			
		||||
        {fillColor: GREEN_FILL, textColor: BLACK_TEXT, ...VALID_CHOICE, bold},
 | 
			
		||||
        INVALID_CHOICE,
 | 
			
		||||
        {fillColor: DEFAULT_FILL, textColor: DEFAULT_TEXT, ...VALID_CHOICE}
 | 
			
		||||
      ]
 | 
			
		||||
    );
 | 
			
		||||
    assert.deepEqual(
 | 
			
		||||
      await getCellTokenStyles(await gu.getCell({rowNum: 3, col: 'B'})),
 | 
			
		||||
      [
 | 
			
		||||
        {fillColor: GREEN_FILL, textColor: BLACK_TEXT, ...VALID_CHOICE, bold}
 | 
			
		||||
      ]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Click save, and check that the new colors are now used in the grid
 | 
			
		||||
    await driver.find('.test-choice-list-entry-save').click();
 | 
			
		||||
    await gu.waitForServer();
 | 
			
		||||
    assert.deepEqual(
 | 
			
		||||
      await getCellTokenStyles(await gu.getCell({rowNum: 1, col: 'B'})),
 | 
			
		||||
      [
 | 
			
		||||
        {fillColor: DARK_GREEN_FILL, textColor: WHITE_TEXT, ...VALID_CHOICE, strikethrough, underline, bold},
 | 
			
		||||
        INVALID_CHOICE,
 | 
			
		||||
        {fillColor: APRICOT_FILL, textColor: APRICOT_TEXT, ...VALID_CHOICE, bold, italic}
 | 
			
		||||
      ]
 | 
			
		||||
    );
 | 
			
		||||
    assert.deepEqual(
 | 
			
		||||
      await getCellTokenStyles(await gu.getCell({rowNum: 3, col: 'B'})),
 | 
			
		||||
      [
 | 
			
		||||
        {fillColor: DARK_GREEN_FILL, textColor: WHITE_TEXT, ...VALID_CHOICE,
 | 
			
		||||
         strikethrough, underline, bold}
 | 
			
		||||
      ]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Open the editor again to make another change.
 | 
			
		||||
    await driver.find('.test-choice-list-entry').click();
 | 
			
		||||
    await gu.waitAppFocus(false);
 | 
			
		||||
 | 
			
		||||
    // Delete 'Apricot', then cancel the change by pressing Escape.
 | 
			
		||||
    await gu.sendKeys(Key.BACK_SPACE);
 | 
			
		||||
    assert.deepEqual(await getEditModeChoiceLabels(), ['Green', 'Blue', 'Black']);
 | 
			
		||||
    await gu.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
    // Check that 'Apricot' is still there and the change wasn't saved.
 | 
			
		||||
    assert.deepEqual(await getChoiceLabels(), ['Green', 'Blue', 'Black', 'Apricot']);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should support undo/redo shortcuts in the choice config editor', async function() {
 | 
			
		||||
    // Open the choice editor.
 | 
			
		||||
    await driver.find('.test-choice-list-entry').click();
 | 
			
		||||
    await gu.waitAppFocus(false);
 | 
			
		||||
 | 
			
		||||
    // Add a few choices.
 | 
			
		||||
    await driver.sendKeys('Foo', Key.ENTER, 'Bar', Key.ENTER, 'Baz', Key.ENTER);
 | 
			
		||||
    assert.deepEqual(await getEditModeChoiceLabels(), ['Green', 'Blue', 'Black', 'Apricot', 'Foo', 'Bar', 'Baz']);
 | 
			
		||||
 | 
			
		||||
    // Undo, verifying the contents of the choice config editor are correct after each invocation.
 | 
			
		||||
    const modKey = await gu.modKey();
 | 
			
		||||
    await gu.sendKeys(Key.chord(modKey, 'z'));
 | 
			
		||||
    assert.deepEqual(await getEditModeChoiceLabels(), ['Green', 'Blue', 'Black', 'Apricot', 'Foo', 'Bar']);
 | 
			
		||||
    await gu.sendKeys(Key.chord(modKey, 'z'));
 | 
			
		||||
    assert.deepEqual(await getEditModeChoiceLabels(), ['Green', 'Blue', 'Black', 'Apricot', 'Foo']);
 | 
			
		||||
    await gu.sendKeys(Key.chord(modKey, 'z'));
 | 
			
		||||
    assert.deepEqual(await getEditModeChoiceLabels(), ['Green', 'Blue', 'Black', 'Apricot']);
 | 
			
		||||
 | 
			
		||||
    // Redo, then undo, verifying at each step.
 | 
			
		||||
    await gu.sendKeys(Key.chord(Key.CONTROL, 'y'));
 | 
			
		||||
    assert.deepEqual(await getEditModeChoiceLabels(), ['Green', 'Blue', 'Black', 'Apricot', 'Foo']);
 | 
			
		||||
    await gu.sendKeys(Key.chord(modKey, 'z'));
 | 
			
		||||
    assert.deepEqual(await getEditModeChoiceLabels(), ['Green', 'Blue', 'Black', 'Apricot']);
 | 
			
		||||
 | 
			
		||||
    // Change the color of 'Apricot' to white with black text, and modify font options
 | 
			
		||||
    const [, , , apricotColorBtn] = await driver
 | 
			
		||||
      .findAll('.test-tokenfield .test-color-button');
 | 
			
		||||
    await apricotColorBtn.click();
 | 
			
		||||
    await gu.setColor(driver.find('.test-fill-input'), 'rgb(255, 255, 255)');
 | 
			
		||||
    await gu.setColor(driver.find('.test-text-input'), 'rgb(0, 0, 0)');
 | 
			
		||||
    await gu.setFont('bold', false);
 | 
			
		||||
    await gu.setFont('italic', false);
 | 
			
		||||
    await gu.setFont('underline', true);
 | 
			
		||||
 | 
			
		||||
    await driver.sendKeys(Key.ENTER);
 | 
			
		||||
    assert.deepEqual(await getEditModeFillColors(), [DARK_GREEN_FILL, BLUE_FILL,  BLACK_FILL, WHITE_FILL]);
 | 
			
		||||
    assert.deepEqual(await getEditModeTextColors(), [WHITE_TEXT,      BLACK_TEXT, WHITE_TEXT, BLACK_TEXT]);
 | 
			
		||||
    assert.deepEqual(await getEditModeFontOptions(), [{bold, underline, strikethrough}, {}, {}, {underline}]);
 | 
			
		||||
 | 
			
		||||
    // Undo, then re-do, verifying after each invocation
 | 
			
		||||
    await driver.find('.test-choice-list-entry .test-tokenfield .test-tokenfield-input').click();
 | 
			
		||||
    await gu.sendKeys(Key.chord(modKey, 'z'));
 | 
			
		||||
    assert.deepEqual(await getEditModeFillColors(), [DARK_GREEN_FILL, BLUE_FILL, BLACK_FILL, APRICOT_FILL]);
 | 
			
		||||
    assert.deepEqual(await getEditModeTextColors(), [WHITE_TEXT, BLACK_TEXT, WHITE_TEXT, APRICOT_TEXT]);
 | 
			
		||||
    assert.deepEqual(await getEditModeFontOptions(), [{bold, underline, strikethrough}, {}, {}, {bold, italic}]);
 | 
			
		||||
    await gu.sendKeys(Key.chord(Key.CONTROL, 'y'));
 | 
			
		||||
    assert.deepEqual(await getEditModeFillColors(), [DARK_GREEN_FILL, BLUE_FILL, BLACK_FILL, WHITE_FILL]);
 | 
			
		||||
    assert.deepEqual(await getEditModeTextColors(), [WHITE_TEXT, BLACK_TEXT, WHITE_TEXT, BLACK_TEXT]);
 | 
			
		||||
    assert.deepEqual(await getEditModeFontOptions(), [{bold, underline, strikethrough}, {}, {}, {underline}]);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should support rich copy/paste in the choice config editor', async function() {
 | 
			
		||||
    // Remove all choices
 | 
			
		||||
    const modKey = await gu.modKey();
 | 
			
		||||
    await gu.sendKeys(Key.chord(modKey, 'a'), Key.BACK_SPACE);
 | 
			
		||||
 | 
			
		||||
    // Add a few new choices
 | 
			
		||||
    await gu.sendKeys('Choice 1', Key.ENTER, 'Choice 2', Key.ENTER, 'Choice 3', Key.ENTER);
 | 
			
		||||
 | 
			
		||||
    // Copy all the choices
 | 
			
		||||
    await gu.sendKeys(Key.chord(modKey, 'a'), await gu.copyKey());
 | 
			
		||||
 | 
			
		||||
    // Delete all the choices, then paste them back and verify no data was lost.
 | 
			
		||||
    await driver.sendKeys(Key.BACK_SPACE);
 | 
			
		||||
    assert.deepEqual(await getEditModeChoiceLabels(), []);
 | 
			
		||||
    await gu.sendKeys(await gu.pasteKey());
 | 
			
		||||
    assert.deepEqual(await getEditModeChoiceLabels(), ['Choice 1', 'Choice 2', 'Choice 3']);
 | 
			
		||||
 | 
			
		||||
    // In Jenkins, clipboard contents are pasted from the system clipboard, which only copies
 | 
			
		||||
    // choices as newline-separated labels. For this reason, we can't check that the color
 | 
			
		||||
    // information also got pasted, because the data is stored elsewhere. In actual use, the
 | 
			
		||||
    // workflow above would copy all the choice data as well, and use it for pasting in the editor.
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should add a new element on a fresh ChoiceList column', async function() {
 | 
			
		||||
    await gu.addColumn("ChoiceList");
 | 
			
		||||
    await gu.setType(gu.exactMatch("Choice List"));
 | 
			
		||||
    const cell = await gu.getCell("ChoiceList", 1);
 | 
			
		||||
    await cell.click();
 | 
			
		||||
    await gu.sendKeys("foo");
 | 
			
		||||
    const plus = await driver.findWait(".test-choice-list-editor-new-item", 100);
 | 
			
		||||
    await plus.click();
 | 
			
		||||
    await gu.sendKeys(Key.ENTER);
 | 
			
		||||
    await gu.waitForServer();
 | 
			
		||||
    assert.equal(await cell.getText(), "foo");
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should add a new element on a fresh Choice column', async function() {
 | 
			
		||||
    await gu.addColumn("Choice");
 | 
			
		||||
    await gu.setType(gu.exactMatch("Choice"));
 | 
			
		||||
    const cell = await gu.getCell("Choice", 1);
 | 
			
		||||
    await cell.click();
 | 
			
		||||
    await gu.sendKeys("foo");
 | 
			
		||||
    const plus = await driver.findWait(".test-choice-editor-new-item", 100);
 | 
			
		||||
    await plus.click();
 | 
			
		||||
    await gu.waitForServer();
 | 
			
		||||
    assert.equal(await cell.getText(), "foo");
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  for (const columnName of ["ChoiceList", "Choice"]) {
 | 
			
		||||
    it(`should allow renaming tokens on ${columnName} column`, gu.revertChanges(async function () {
 | 
			
		||||
      // Helper that converts ChoiceList to choice-list
 | 
			
		||||
      const editorDashedName = columnName.toLowerCase().replace(/list/, "-list");
 | 
			
		||||
      // Add two new options: one, two.
 | 
			
		||||
      await gu.getCell(columnName, 2).click();
 | 
			
		||||
      await gu.sendKeys("one");
 | 
			
		||||
      await driver.findWait(`.test-${editorDashedName}-editor-new-item`, 300).click();
 | 
			
		||||
      if (columnName === "ChoiceList") {
 | 
			
		||||
        await gu.sendKeys(Key.ENTER);
 | 
			
		||||
      }
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      await gu.getCell(columnName, 3).click();
 | 
			
		||||
      await gu.sendKeys("two");
 | 
			
		||||
      await driver.findWait(`.test-${editorDashedName}-editor-new-item`, 300).click();
 | 
			
		||||
      if (columnName === "ChoiceList") {
 | 
			
		||||
        await gu.sendKeys(Key.ENTER);
 | 
			
		||||
      }
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // Make sure right panel is open and has right focus.
 | 
			
		||||
      await gu.toggleSidePanel("right", "open");
 | 
			
		||||
      await driver.find(".test-right-tab-field").click();
 | 
			
		||||
      // Rename one to three.
 | 
			
		||||
      await editChoiceEntries();
 | 
			
		||||
      await renameEntry("one", "three");
 | 
			
		||||
      await saveChoiceEntries();
 | 
			
		||||
      assert.deepEqual(await gu.getVisibleGridCells({ rowNums: [1, 2, 3], cols: [columnName] }), [
 | 
			
		||||
        "foo",
 | 
			
		||||
        "three",
 | 
			
		||||
        "two",
 | 
			
		||||
      ]);
 | 
			
		||||
 | 
			
		||||
      // Rename foo to bar, two to four, and three to eight, press undo 3 times
 | 
			
		||||
      // and make sure nothing changes.
 | 
			
		||||
      await editChoiceEntries();
 | 
			
		||||
      await renameEntry("foo", "bar");
 | 
			
		||||
      await renameEntry("three", "eight");
 | 
			
		||||
      await renameEntry("two", "four");
 | 
			
		||||
      assert.deepEqual(await getEditModeChoiceLabels(), ["bar", "eight", "four"]);
 | 
			
		||||
      const undoKey = Key.chord(await gu.modKey(), "z");
 | 
			
		||||
      await gu.sendKeys(undoKey);
 | 
			
		||||
      await gu.sendKeys(undoKey);
 | 
			
		||||
      await gu.sendKeys(undoKey);
 | 
			
		||||
      assert.deepEqual(await getEditModeChoiceLabels(), ["foo", "three", "two"]);
 | 
			
		||||
 | 
			
		||||
      // Make sure we can copy and paste without adding new item
 | 
			
		||||
      await clickEntry('foo');
 | 
			
		||||
      await gu.sendKeys(await gu.cutKey());
 | 
			
		||||
      await gu.sendKeys(await gu.pasteKey());
 | 
			
		||||
      await gu.sendKeys(await gu.pasteKey());
 | 
			
		||||
      await gu.sendKeys(Key.ENTER);
 | 
			
		||||
      await clickEntry('three');
 | 
			
		||||
      await gu.sendKeys(await gu.copyKey());
 | 
			
		||||
      await clickEntry('two');
 | 
			
		||||
      await gu.sendKeys(Key.ARROW_RIGHT);
 | 
			
		||||
      await gu.sendKeys(await gu.pasteKey());
 | 
			
		||||
      await gu.sendKeys(Key.ENTER);
 | 
			
		||||
      assert.deepEqual(await getEditModeChoiceLabels(), ["foofoo", "three", "twothree"]);
 | 
			
		||||
      await saveChoiceEntries();
 | 
			
		||||
      assert.deepEqual(await gu.getVisibleGridCells({ rowNums: [1, 2, 3], cols: [columnName] }), [
 | 
			
		||||
        "foofoo",
 | 
			
		||||
        "three",
 | 
			
		||||
        "twothree",
 | 
			
		||||
      ]);
 | 
			
		||||
 | 
			
		||||
      // Rename to bar, four and eight and do the change.
 | 
			
		||||
      await editChoiceEntries();
 | 
			
		||||
      await renameEntry("foofoo", "bar");
 | 
			
		||||
      await renameEntry("twothree", "four");
 | 
			
		||||
      await renameEntry("three", "eight");
 | 
			
		||||
      await saveChoiceEntries();
 | 
			
		||||
      assert.deepEqual(await gu.getVisibleGridCells({ rowNums: [1, 2, 3], cols: [columnName] }), [
 | 
			
		||||
        "bar",
 | 
			
		||||
        "eight",
 | 
			
		||||
        "four",
 | 
			
		||||
      ]);
 | 
			
		||||
 | 
			
		||||
      // Add color to bar, save it, change to foo and make sure the color is still there.
 | 
			
		||||
      await editChoiceEntries();
 | 
			
		||||
      const [barColor] = await driver.findAll(".test-tokenfield .test-color-button");
 | 
			
		||||
      await barColor.click();
 | 
			
		||||
      await gu.setColor(driver.find(".test-text-input"), "rgb(70, 13, 129)");
 | 
			
		||||
      await driver.sendKeys(Key.ENTER);
 | 
			
		||||
      await renameEntry("bar", "foo");
 | 
			
		||||
      await saveChoiceEntries();
 | 
			
		||||
      await editChoiceEntries();
 | 
			
		||||
      const [fooColorText] = await getEditModeTextColors();
 | 
			
		||||
      assert.equal(fooColorText, "rgba(70, 13, 129, 1)");
 | 
			
		||||
 | 
			
		||||
      // Start renaming, but cancel out of the editor with two presses of the Escape key;
 | 
			
		||||
      // a previous bug caused focus to be lost after the first Escape, making it impossible
 | 
			
		||||
      // to close the editor with a subsequent press of Escape.
 | 
			
		||||
      await editChoiceEntries();
 | 
			
		||||
      await clickEntry("foo");
 | 
			
		||||
      await gu.sendKeys("food");
 | 
			
		||||
      await gu.sendKeys(Key.ESCAPE, Key.ESCAPE);
 | 
			
		||||
      assert.isFalse(await driver.find(".test-choice-list-entry-save").isPresent());
 | 
			
		||||
 | 
			
		||||
    },
 | 
			
		||||
    // Test if the column is reverted to state before the test
 | 
			
		||||
    () => gu.getVisibleGridCells({rowNums: [1, 2, 3], cols: [columnName]})));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  it('should allow renaming multiple tokens on ChoiceList', gu.revertChanges(async function() {
 | 
			
		||||
    // Work on ChoiceList column, add one new option "one"
 | 
			
		||||
    await gu.getCell("ChoiceList", 2).click();
 | 
			
		||||
    await gu.sendKeys("one");
 | 
			
		||||
    await driver.findWait(`.test-choice-list-editor-new-item`, 300).click();
 | 
			
		||||
    await gu.sendKeys(Key.ENTER);
 | 
			
		||||
    await gu.waitForServer();
 | 
			
		||||
    await gu.getCell("ChoiceList", 3).click();
 | 
			
		||||
    await gu.sendKeys("one", Key.ENTER, "foo", Key.ENTER);
 | 
			
		||||
    await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
    // Make sure right panel is open and has right focus.
 | 
			
		||||
    await gu.toggleSidePanel('right', 'open');
 | 
			
		||||
    await driver.find('.test-right-tab-field').click();
 | 
			
		||||
 | 
			
		||||
    // rename one to three
 | 
			
		||||
    await editChoiceEntries();
 | 
			
		||||
    await renameEntry("one", "three");
 | 
			
		||||
    await renameEntry("foo", "four");
 | 
			
		||||
    await saveChoiceEntries();
 | 
			
		||||
    assert.deepEqual(await gu.getVisibleGridCells({rowNums: [1, 2, 3], cols: ['ChoiceList']}), [
 | 
			
		||||
      'four',
 | 
			
		||||
      'three',
 | 
			
		||||
      'three\nfour',
 | 
			
		||||
    ]);
 | 
			
		||||
  },
 | 
			
		||||
  // Test if the column is reverted to state before the test
 | 
			
		||||
  () => gu.getVisibleGridCells({rowNums: [1, 2, 3], cols: ['ChoiceList']})));
 | 
			
		||||
 | 
			
		||||
  it('should rename saved filters', gu.revertChanges(async function() {
 | 
			
		||||
    // Make sure right panel is open and has focus.
 | 
			
		||||
    await gu.toggleSidePanel('right', 'open');
 | 
			
		||||
    await driver.find('.test-right-tab-field').click();
 | 
			
		||||
 | 
			
		||||
    // Work on ChoiceList column, add two new options: one, two
 | 
			
		||||
    await gu.getCell("ChoiceList", 2).click();
 | 
			
		||||
    await gu.sendKeys("one");
 | 
			
		||||
    await driver.findWait(`.test-choice-list-editor-new-item`, 300).click();
 | 
			
		||||
    await gu.sendKeys(Key.ENTER);
 | 
			
		||||
    await gu.getCell("ChoiceList", 3).click();
 | 
			
		||||
    await gu.sendKeys("one", Key.ENTER, "foo", Key.ENTER, Key.ENTER);
 | 
			
		||||
    await gu.waitForServer();
 | 
			
		||||
    // Make sure column looks like this:
 | 
			
		||||
    assert.deepEqual(await gu.getVisibleGridCells({rowNums: [1, 2, 3, 4], cols: ['ChoiceList']}), [
 | 
			
		||||
      'foo',
 | 
			
		||||
      'one',
 | 
			
		||||
      'one\nfoo',
 | 
			
		||||
      '' // add row
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    // Filter by single value and save.
 | 
			
		||||
    await gu.filterBy('ChoiceList', true, [/one/]);
 | 
			
		||||
 | 
			
		||||
    // Duplicate page, to make sure filters are also renamed in a new section.
 | 
			
		||||
    await gu.openPageMenu('Table1');
 | 
			
		||||
    await driver.find('.test-docpage-duplicate').click();
 | 
			
		||||
    await driver.find('.test-modal-confirm').click();
 | 
			
		||||
    await driver.findContentWait('.test-docpage-label', /copy/, 2000);
 | 
			
		||||
    await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
    // Go back to Table1
 | 
			
		||||
    await gu.getPageItem('Table1').click();
 | 
			
		||||
    // Make sure grid is filtered
 | 
			
		||||
    assert.deepEqual(await gu.getVisibleGridCells({rowNums: [1, 2, 3], cols: ['ChoiceList']}), [
 | 
			
		||||
      'one',
 | 
			
		||||
      'one\nfoo',
 | 
			
		||||
      '' // new row
 | 
			
		||||
    ]);
 | 
			
		||||
    // Rename one to five, foo to bar
 | 
			
		||||
    await editChoiceEntries();
 | 
			
		||||
    await renameEntry("one", "five");
 | 
			
		||||
    await renameEntry("foo", "bar");
 | 
			
		||||
    await saveChoiceEntries();
 | 
			
		||||
    // Make sure that there are still two records - filter should be changed to new values.
 | 
			
		||||
    assert.deepEqual(await gu.getVisibleGridCells({rowNums: [1, 2, 3], cols: ['ChoiceList']}), [
 | 
			
		||||
      'five',
 | 
			
		||||
      'five\nbar',
 | 
			
		||||
      '' // new row
 | 
			
		||||
    ]);
 | 
			
		||||
    // Make sure that it also renamed filters in diffrent section.
 | 
			
		||||
    await gu.getPageItem('Table1 (copy)').click();
 | 
			
		||||
    assert.deepEqual(await gu.getVisibleGridCells({rowNums: [1, 2, 3], cols: ['ChoiceList']}), [
 | 
			
		||||
      'five',
 | 
			
		||||
      'five\nbar',
 | 
			
		||||
      '' // new row
 | 
			
		||||
    ]);
 | 
			
		||||
    // Go back to previous names, filter still should work.
 | 
			
		||||
    await gu.undo();
 | 
			
		||||
    assert.deepEqual(await gu.getVisibleGridCells({rowNums: [1, 2, 3], cols: ['ChoiceList']}), [
 | 
			
		||||
      'one',
 | 
			
		||||
      'one\nfoo',
 | 
			
		||||
      '' // new row
 | 
			
		||||
    ]);
 | 
			
		||||
  },
 | 
			
		||||
  // Test if the column is reverted to state before the test
 | 
			
		||||
  () => gu.getVisibleGridCells({rowNums: [1, 2, 3], cols: ['ChoiceList']})));
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										566
									
								
								test/nbrowser/ReferenceColumns.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										566
									
								
								test/nbrowser/ReferenceColumns.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,566 @@
 | 
			
		||||
import {assert, driver, Key, stackWrapFunc} from 'mocha-webdriver';
 | 
			
		||||
import * as gu from 'test/nbrowser/gristUtils';
 | 
			
		||||
import {Session} from 'test/nbrowser/gristUtils';
 | 
			
		||||
import {server, setupTestSuite} from 'test/nbrowser/testUtils';
 | 
			
		||||
 | 
			
		||||
describe('ReferenceColumns', function() {
 | 
			
		||||
  this.timeout(20000);
 | 
			
		||||
  setupTestSuite();
 | 
			
		||||
  let session: Session;
 | 
			
		||||
  const cleanup = setupTestSuite({team: true});
 | 
			
		||||
 | 
			
		||||
  describe('rendering', function() {
 | 
			
		||||
    before(async function() {
 | 
			
		||||
      session = await gu.session().teamSite.login();
 | 
			
		||||
      await session.tempDoc(cleanup, 'Favorite_Films.grist');
 | 
			
		||||
 | 
			
		||||
      await gu.toggleSidePanel('right');
 | 
			
		||||
      await driver.find('.test-config-data').click();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should render Row ID values as TableId[RowId]', async function() {
 | 
			
		||||
      await driver.find('.test-right-tab-field').click();
 | 
			
		||||
      await driver.find('.mod-add-column').click();
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      await gu.setType(/Reference/);
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      await gu.enterGridRows({col: 3, rowNum: 1}, [['1'], ['2'], ['3'], ['4']]);
 | 
			
		||||
      assert.deepEqual(await gu.getVisibleGridCells(3, [1, 2, 3, 4, 5, 6]),
 | 
			
		||||
        ['Films[1]', 'Films[2]', 'Films[3]', 'Films[4]', '', '']);
 | 
			
		||||
      await driver.find('.test-fbuilder-ref-table-select').click();
 | 
			
		||||
      await driver.findContent('.test-select-row', /Friends/).click();
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // These are now invalid cells containing AltText such as 'Films[1]'
 | 
			
		||||
      // We don't simply convert Films[1] -> Friends[1]
 | 
			
		||||
      assert.deepEqual(await gu.getVisibleGridCells(3, [1, 2, 3, 4, 5, 6]),
 | 
			
		||||
        ['Films[1]', 'Films[2]', 'Films[3]', 'Films[4]', '', '']);
 | 
			
		||||
 | 
			
		||||
      await driver.find('.test-type-transform-apply').click();
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      await driver.find('.test-fbuilder-ref-col-select').click();
 | 
			
		||||
      await driver.findContent('.test-select-row', /Name/).click();
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.deepEqual(await gu.getVisibleGridCells(3, [1, 2, 3, 4, 5, 6]),
 | 
			
		||||
        ['Films[1]', 'Films[2]', 'Films[3]', 'Films[4]', '', '']);
 | 
			
		||||
      await gu.getCell(3, 5).click();
 | 
			
		||||
      await driver.sendKeys('Roger');
 | 
			
		||||
      await driver.sendKeys(Key.ENTER);
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // 'Roger' is an actual reference
 | 
			
		||||
      assert.deepEqual(await gu.getVisibleGridCells(3, [1, 2, 3, 4, 5, 6]),
 | 
			
		||||
        ['Films[1]', 'Films[2]', 'Films[3]', 'Films[4]', 'Roger', '']);
 | 
			
		||||
 | 
			
		||||
      await driver.find('.test-fbuilder-ref-col-select').click();
 | 
			
		||||
      await driver.findContent('.test-select-row', /Row ID/).click();
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // 'Friends[1]' is an actual reference, the rest are invalid
 | 
			
		||||
      assert.deepEqual(await gu.getVisibleGridCells(3, [1, 2, 3, 4, 5, 6]),
 | 
			
		||||
        ['Films[1]', 'Films[2]', 'Films[3]', 'Films[4]', 'Friends[1]', '']);
 | 
			
		||||
 | 
			
		||||
      await driver.find('.test-fbuilder-ref-col-select').click();
 | 
			
		||||
      await driver.findContent('.test-select-row', /Name/).click();
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.deepEqual(await gu.getVisibleGridCells(3, [1, 2, 3, 4, 5, 6]),
 | 
			
		||||
        ['Films[1]', 'Films[2]', 'Films[3]', 'Films[4]', 'Roger', '']);
 | 
			
		||||
 | 
			
		||||
      await gu.undo();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should allow entering numeric id before target table is loaded', async function() {
 | 
			
		||||
      // Refresh the document.
 | 
			
		||||
      await driver.navigate().refresh();
 | 
			
		||||
      await gu.waitForDocToLoad();
 | 
			
		||||
 | 
			
		||||
      // Now pause the server
 | 
			
		||||
      const cell = gu.getCell({col: 'A', rowNum: 1});
 | 
			
		||||
      await server.pauseUntil(async () => {
 | 
			
		||||
        assert.equal(await cell.getText(), 'Films[1]');
 | 
			
		||||
        await cell.click();
 | 
			
		||||
        await gu.sendKeys('5');
 | 
			
		||||
        // Check that the autocomplete has no items yet.
 | 
			
		||||
        assert.isEmpty(await driver.findAll('.test-autocomplete .test-ref-editor-new-item'));
 | 
			
		||||
        await gu.sendKeys(Key.ENTER);
 | 
			
		||||
      });
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.equal(await cell.getText(), 'Friends[5]');
 | 
			
		||||
 | 
			
		||||
      await gu.undo();
 | 
			
		||||
      assert.equal(await cell.getText(), 'Films[1]');
 | 
			
		||||
 | 
			
		||||
      // Once server is responsive, a valid value should not offer a "new item".
 | 
			
		||||
      await cell.click();
 | 
			
		||||
      await gu.sendKeys('5');
 | 
			
		||||
      await driver.findWait('.test-ref-editor-item', 500);
 | 
			
		||||
      assert.isFalse(await driver.find('.test-ref-editor-new-item').isPresent());
 | 
			
		||||
      await gu.sendKeys(Key.ENTER);
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.equal(await cell.getText(), 'Friends[5]');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it(`should show '[Blank]' if the referenced item is blank`, async function() {
 | 
			
		||||
      // Open the All page.
 | 
			
		||||
      await driver.findContentWait('.test-treeview-itemHeader', /All/, 2000).click();
 | 
			
		||||
      await gu.waitForDocToLoad();
 | 
			
		||||
 | 
			
		||||
      // Clear the cells in Films record containing Avatar and Alien.
 | 
			
		||||
      await gu.getCell('Title', 3, 'Films record').doClick();
 | 
			
		||||
      await gu.sendKeys(Key.BACK_SPACE);
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      await gu.sendKeys(Key.ARROW_DOWN, Key.BACK_SPACE);
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // Check that all references to Avatar and Alien now show '[Blank]'.
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await gu.getVisibleGridCells('Favorite Film', [1, 2, 3, 4, 5, 6], 'Friends record'),
 | 
			
		||||
        [
 | 
			
		||||
          'Forrest Gump',
 | 
			
		||||
          'Toy Story',
 | 
			
		||||
          '[Blank]',
 | 
			
		||||
          'The Dark Knight',
 | 
			
		||||
          'Forrest Gump',
 | 
			
		||||
          '[Blank]'
 | 
			
		||||
        ]
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      // Check that '[Blank]' is not shown when the reference editor is open.
 | 
			
		||||
      await gu.getCell('Favorite Film', 3, 'Friends record').doClick();
 | 
			
		||||
      await gu.sendKeys(Key.ENTER);
 | 
			
		||||
      assert.equal(await driver.find('.celleditor_text_editor').value(), '');
 | 
			
		||||
      await gu.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      // Undo (twice), and check that it shows Avatar and Alien again.
 | 
			
		||||
      await gu.undo(2);
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await gu.getVisibleGridCells('Favorite Film', [1, 2, 3, 4, 5, 6], 'Friends record'),
 | 
			
		||||
        [
 | 
			
		||||
          'Forrest Gump',
 | 
			
		||||
          'Toy Story',
 | 
			
		||||
          'Avatar',
 | 
			
		||||
          'The Dark Knight',
 | 
			
		||||
          'Forrest Gump',
 | 
			
		||||
          'Alien'
 | 
			
		||||
        ]
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('autocomplete', function() {
 | 
			
		||||
    const getACOptions = stackWrapFunc(async (limit?: number) => {
 | 
			
		||||
      await driver.findWait('.test-ref-editor-item', 1000);
 | 
			
		||||
      return (await driver.findAll('.test-ref-editor-item', el => el.getText())).slice(0, limit);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    before(async function() {
 | 
			
		||||
      await session.tempDoc(cleanup, 'Ref-AC-Test.grist');
 | 
			
		||||
      await gu.toggleSidePanel('right', 'close');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should open to correct item selected, and leave it unchanged on Enter', async function() {
 | 
			
		||||
      const checkRefCell = stackWrapFunc(async (col: string, rowNum: number, expValue: string) => {
 | 
			
		||||
        // Click cell and open for editing.
 | 
			
		||||
        const cell = await gu.getCell({section: 'References', col, rowNum}).doClick();
 | 
			
		||||
        assert.equal(await cell.getText(), expValue);
 | 
			
		||||
        await driver.sendKeys(Key.ENTER);
 | 
			
		||||
        // Wait for expected value to appear in the list; check that it's selected.
 | 
			
		||||
        const match = await driver.findContentWait('.test-ref-editor-item', expValue, 1000);
 | 
			
		||||
        assert.equal(await match.matches('.selected'), true);
 | 
			
		||||
        // Save the value.
 | 
			
		||||
        await driver.sendKeys(Key.ENTER);
 | 
			
		||||
        await gu.waitForServer();
 | 
			
		||||
        assert.equal(await cell.getText(), expValue);
 | 
			
		||||
        // Assert that the undo is disabled, i.e. no action was generated.
 | 
			
		||||
        assert.equal(await driver.find('.test-undo').matches('[class*=-disabled]'), true);
 | 
			
		||||
      });
 | 
			
		||||
      await checkRefCell('Color', 1, 'Dark Slate Blue');
 | 
			
		||||
      await checkRefCell('ColorCode', 2, '#808080');
 | 
			
		||||
      await checkRefCell('XNum', 3, '2019-11-05');
 | 
			
		||||
      await checkRefCell('School', 1, 'TECHNOLOGY, ARTS AND SCIENCES STUDIO');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should render first items when opening empty cell', async function() {
 | 
			
		||||
      await driver.sendKeys(Key.HOME);
 | 
			
		||||
 | 
			
		||||
      let cell = await gu.getCell({section: 'References', col: 'Color', rowNum: 4}).doClick();
 | 
			
		||||
      assert.equal(await cell.getText(), '');
 | 
			
		||||
      await driver.sendKeys(Key.ENTER);
 | 
			
		||||
      // Check the first few items.
 | 
			
		||||
      assert.deepEqual(await getACOptions(3), ["Alice Blue", "Añil", "Aqua"]);
 | 
			
		||||
      // No item is selected.
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-item.selected').isPresent(), false);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      cell = await gu.getCell({section: 'References', col: 'School', rowNum: 6}).doClick();
 | 
			
		||||
      assert.equal(await cell.getText(), '');
 | 
			
		||||
      await driver.sendKeys(Key.ENTER);
 | 
			
		||||
      // Check the first few items; should be sorted alphabetically.
 | 
			
		||||
      assert.deepEqual(await getACOptions(3),
 | 
			
		||||
        ["2 SCHOOL", "4 SCHOOL", "47 AMER SIGN LANG & ENG LOWER "]);
 | 
			
		||||
      // No item is selected.
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-item.selected').isPresent(), false);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should save correct item on click', async function() {
 | 
			
		||||
      await driver.sendKeys(Key.HOME);
 | 
			
		||||
 | 
			
		||||
      // Edit a cell by double-clicking.
 | 
			
		||||
      let cell = await gu.getCell({section: 'References', col: 'Color', rowNum: 2}).doClick();
 | 
			
		||||
      await driver.withActions(a => a.doubleClick(cell));
 | 
			
		||||
      assert.equal(await driver.findWait('.test-ref-editor-item.selected', 1000).getText(), 'Red');
 | 
			
		||||
 | 
			
		||||
      // Scroll to another item and click it.
 | 
			
		||||
      let item = driver.findContent('.test-ref-editor-item', 'Rosy Brown');
 | 
			
		||||
      await gu.scrollIntoView(item);
 | 
			
		||||
      await item.click();
 | 
			
		||||
 | 
			
		||||
      // It should get saved; and undo should restore the previous value.
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.equal(await cell.getText(), 'Rosy Brown');
 | 
			
		||||
      await gu.undo();
 | 
			
		||||
      assert.equal(await cell.getText(), 'Red');
 | 
			
		||||
 | 
			
		||||
      // Edit another cell by starting to type.
 | 
			
		||||
      cell = await gu.getCell({section: 'References', col: 'Color', rowNum: 4}).doClick();
 | 
			
		||||
      await driver.sendKeys("gr");
 | 
			
		||||
      await driver.findWait('.test-ref-editor-item', 1000);
 | 
			
		||||
      item = driver.findContent('.test-ref-editor-item', 'Medium Sea Green');
 | 
			
		||||
      await gu.scrollIntoView(item);
 | 
			
		||||
      await item.click();
 | 
			
		||||
 | 
			
		||||
      // It should get saved; and undo should restore the previous value.
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.equal(await cell.getText(), 'Medium Sea Green');
 | 
			
		||||
      await gu.undo();
 | 
			
		||||
      assert.equal(await cell.getText(), '');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should save correct item after selecting with arrow keys', async function() {
 | 
			
		||||
      // Same as the previous test, but instead of clicking items, select item using arrow keys.
 | 
			
		||||
 | 
			
		||||
      // Edit a cell by double-clicking.
 | 
			
		||||
      let cell = await gu.getCell({section: 'References', col: 'Color', rowNum: 2}).doClick();
 | 
			
		||||
      await driver.withActions(a => a.doubleClick(cell));
 | 
			
		||||
      assert.equal(await driver.findWait('.test-ref-editor-item.selected', 1000).getText(), 'Red');
 | 
			
		||||
 | 
			
		||||
      // Move to another item and hit Enter
 | 
			
		||||
      await driver.sendKeys(Key.DOWN, Key.DOWN, Key.DOWN, Key.DOWN, Key.DOWN);
 | 
			
		||||
      assert.equal(await driver.findWait('.test-ref-editor-item.selected', 1000).getText(), 'Pale Violet Red');
 | 
			
		||||
      await driver.sendKeys(Key.ENTER);
 | 
			
		||||
 | 
			
		||||
      // It should get saved; and undo should restore the previous value.
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.equal(await cell.getText(), 'Pale Violet Red');
 | 
			
		||||
      await gu.undo();
 | 
			
		||||
      assert.equal(await cell.getText(), 'Red');
 | 
			
		||||
 | 
			
		||||
      // Edit another cell by starting to type.
 | 
			
		||||
      cell = await gu.getCell({section: 'References', col: 'Color', rowNum: 4}).doClick();
 | 
			
		||||
      await driver.sendKeys("gr");
 | 
			
		||||
      await driver.findWait('.test-ref-editor-item', 1000);
 | 
			
		||||
      await driver.sendKeys(Key.UP, Key.UP, Key.UP, Key.UP, Key.UP);
 | 
			
		||||
      assert.equal(await driver.findWait('.test-ref-editor-item.selected', 1000).getText(), 'Chocolate');
 | 
			
		||||
      await driver.sendKeys(Key.ENTER);
 | 
			
		||||
 | 
			
		||||
      // It should get saved; and undo should restore the previous value.
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.equal(await cell.getText(), 'Chocolate');
 | 
			
		||||
      await gu.undo();
 | 
			
		||||
      assert.equal(await cell.getText(), '');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should return to text-as-typed when nothing is selected', async function() {
 | 
			
		||||
      const cell = await gu.getCell({section: 'References', col: 'Color', rowNum: 2}).doClick();
 | 
			
		||||
      await driver.sendKeys("da");
 | 
			
		||||
      assert.deepEqual(await getACOptions(2), ["Dark Blue", "Dark Cyan"]);
 | 
			
		||||
 | 
			
		||||
      // Check that the first item is highlighted by default.
 | 
			
		||||
      assert.equal(await driver.find('.celleditor_text_editor').value(), 'da');
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-item.selected').getText(), 'Dark Blue');
 | 
			
		||||
 | 
			
		||||
      // Select second item. Both the textbox and the dropdown show the selection.
 | 
			
		||||
      await driver.sendKeys(Key.DOWN);
 | 
			
		||||
      assert.equal(await driver.find('.celleditor_text_editor').value(), 'Dark Cyan');
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-item.selected').getText(), 'Dark Cyan');
 | 
			
		||||
 | 
			
		||||
      // Move back to no-selection state.
 | 
			
		||||
      await driver.sendKeys(Key.UP, Key.UP);
 | 
			
		||||
      assert.equal(await driver.find('.celleditor_text_editor').value(), 'da');
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-item.selected').isPresent(), false);
 | 
			
		||||
 | 
			
		||||
      // Mouse over an item.
 | 
			
		||||
      await driver.findContent('.test-ref-editor-item', /Dark Gray/).mouseMove();
 | 
			
		||||
      assert.equal(await driver.find('.celleditor_text_editor').value(), 'Dark Gray');
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-item.selected').getText(), 'Dark Gray');
 | 
			
		||||
 | 
			
		||||
      // Mouse back out of the dropdown
 | 
			
		||||
      await driver.find('.celleditor_text_editor').mouseMove();
 | 
			
		||||
      assert.equal(await driver.find('.celleditor_text_editor').value(), 'da');
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-item.selected').isPresent(), false);
 | 
			
		||||
 | 
			
		||||
      // Click away to save the typed-in text.
 | 
			
		||||
      await gu.getCell({section: 'References', col: 'Color', rowNum: 1}).doClick();
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.equal(await cell.getText(), "da");
 | 
			
		||||
      assert.equal(await cell.find('.field_clip').matches('.invalid'), true);
 | 
			
		||||
 | 
			
		||||
      await gu.undo();
 | 
			
		||||
      assert.equal(await cell.getText(), "Red");
 | 
			
		||||
      assert.equal(await cell.find('.field_clip').matches('.invalid'), false);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should save text as typed when nothing is selected', async function() {
 | 
			
		||||
      const cell = await gu.getCell({section: 'References', col: 'Color', rowNum: 1}).doClick();
 | 
			
		||||
      await driver.sendKeys("lavender ", Key.ENTER);
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.equal(await cell.getText(), "Lavender");
 | 
			
		||||
      await gu.undo();
 | 
			
		||||
      assert.equal(await cell.getText(), "Dark Slate Blue");
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should offer an add-new option when no good match', async function() {
 | 
			
		||||
      const cell = await gu.getCell({section: 'References', col: 'Color', rowNum: 2}).doClick();
 | 
			
		||||
      await driver.sendKeys("pinkish");
 | 
			
		||||
      // There are inexact matches.
 | 
			
		||||
      assert.deepEqual(await getACOptions(3),
 | 
			
		||||
        ["Pink", "Deep Pink", "Hot Pink"]);
 | 
			
		||||
      // Nothing is selected, and the "add new" item is present.
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-item.selected').isPresent(), false);
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-new-item').getText(), "pinkish");
 | 
			
		||||
 | 
			
		||||
      // Click the "add new" item. The new value should be saved, and should not appear invalid.
 | 
			
		||||
      await driver.find('.test-ref-editor-new-item').click();
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.equal(await cell.getText(), "pinkish");
 | 
			
		||||
      assert.equal(await cell.find('.field_clip').matches('.invalid'), false);
 | 
			
		||||
 | 
			
		||||
      // Requires 2 undos, because adding the "pinkish" record is a separate action. TODO these
 | 
			
		||||
      // actions should be bundled.
 | 
			
		||||
      await gu.undo(2);
 | 
			
		||||
      assert.equal(await cell.getText(), "Red");
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should offer an add-new option when opening alt-text', async function() {
 | 
			
		||||
      const cell = await gu.getCell({section: 'References', col: 'Color', rowNum: 2}).doClick();
 | 
			
		||||
 | 
			
		||||
      // Enter and invalid value and save without clicking "add new".
 | 
			
		||||
      await driver.sendKeys("super pink", Key.ENTER);
 | 
			
		||||
 | 
			
		||||
      // It should be saved but appear invalid (as alt-text).
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.equal(await cell.getText(), "super pink");
 | 
			
		||||
      assert.equal(await cell.find('.field_clip').matches('.invalid'), true);
 | 
			
		||||
 | 
			
		||||
      // Open the cell again. The "Add New" option should be there.
 | 
			
		||||
      await driver.withActions(a => a.doubleClick(cell));
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-new-item').getText(), "super pink");
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-item.selected').isPresent(), false);
 | 
			
		||||
 | 
			
		||||
      // Select "add new" (this time with arrow keys), and save.
 | 
			
		||||
      await driver.sendKeys(Key.UP);
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-new-item').matches('.selected'), true);
 | 
			
		||||
      await driver.sendKeys(Key.ENTER);
 | 
			
		||||
 | 
			
		||||
      // Once "add new" is clicked, the "super pink" no longer appears as invalid.
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.equal(await cell.getText(), "super pink");
 | 
			
		||||
      assert.equal(await cell.find('.field_clip').matches('.invalid'), false);
 | 
			
		||||
 | 
			
		||||
      await gu.undo(3);
 | 
			
		||||
      assert.equal(await cell.getText(), "Red");
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should not offer an add-new option when target is a formula', async function() {
 | 
			
		||||
      // Click on an alt-text cell.
 | 
			
		||||
      const cell = await gu.getCell({section: 'References', col: 'Color', rowNum: 3}).doClick();
 | 
			
		||||
      assert.equal(await cell.getText(), "hello");
 | 
			
		||||
      assert.equal(await cell.find('.field_clip').matches('.invalid'), true);
 | 
			
		||||
 | 
			
		||||
      await driver.sendKeys(Key.ENTER);
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-new-item').getText(), "hello");
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      // Change the visible column to the formula column "C2".
 | 
			
		||||
      await gu.toggleSidePanel('right', 'open');
 | 
			
		||||
      await driver.find('.test-right-tab-field').click();
 | 
			
		||||
      await driver.find('.test-fbuilder-ref-col-select').click();
 | 
			
		||||
      await driver.findContent('.test-select-row', /C2/).click();
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // Check that for the same cell, the dropdown no longer has an "add new" option.
 | 
			
		||||
      await cell.click();
 | 
			
		||||
      await driver.sendKeys(Key.ENTER);
 | 
			
		||||
      assert.equal(await driver.find('.celleditor_text_editor').value(), 'hello');
 | 
			
		||||
      await driver.findWait('.test-ref-editor-item', 1000);
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-item.selected').isPresent(), false);
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-new-item').isPresent(), false);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      await gu.undo();
 | 
			
		||||
      await gu.toggleSidePanel('right', 'close');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should offer items ordered by best match', async function() {
 | 
			
		||||
      let cell = await gu.getCell({section: 'References', col: 'Color', rowNum: 1}).doClick();
 | 
			
		||||
      assert.equal(await cell.getText(), 'Dark Slate Blue');
 | 
			
		||||
      await driver.sendKeys(Key.ENTER);
 | 
			
		||||
      assert.deepEqual(await getACOptions(4),
 | 
			
		||||
        ['Dark Slate Blue', 'Dark Slate Gray', 'Slate Blue', 'Medium Slate Blue']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      await driver.sendKeys('blac');
 | 
			
		||||
      assert.deepEqual(await getACOptions(6),
 | 
			
		||||
        ['Black', 'Blanched Almond', 'Blue', 'Blue Violet', 'Alice Blue', 'Cadet Blue']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      cell = await gu.getCell({section: 'References', col: 'Color', rowNum: 3}).doClick();
 | 
			
		||||
      assert.equal(await cell.getText(), 'hello');    // Alt-text
 | 
			
		||||
      await driver.sendKeys(Key.ENTER);
 | 
			
		||||
      assert.deepEqual(await getACOptions(2),
 | 
			
		||||
        ['Honeydew', 'Hot Pink']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      cell = await gu.getCell({section: 'References', col: 'ColorCode', rowNum: 2}).doClick();
 | 
			
		||||
      assert.equal(await cell.getText(), '#808080');
 | 
			
		||||
      await driver.sendKeys(Key.ENTER);
 | 
			
		||||
      assert.deepEqual(await getACOptions(5),
 | 
			
		||||
        ['#808080', '#808000', '#800000', '#800080', '#87CEEB']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      cell = await gu.getCell({section: 'References', col: 'XNum', rowNum: 2}).doClick();
 | 
			
		||||
      assert.equal(await cell.getText(), '2019-04-29');
 | 
			
		||||
      await driver.sendKeys(Key.ENTER);
 | 
			
		||||
      assert.deepEqual(await getACOptions(4),
 | 
			
		||||
        ['2019-04-29', '2020-04-29', '2019-11-05', '2020-04-28']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should update choices as user types into textbox', async function() {
 | 
			
		||||
      let cell = await gu.getCell({section: 'References', col: 'School', rowNum: 1}).doClick();
 | 
			
		||||
      assert.equal(await cell.getText(), 'TECHNOLOGY, ARTS AND SCIENCES STUDIO');
 | 
			
		||||
      await driver.sendKeys(Key.ENTER);
 | 
			
		||||
      assert.deepEqual(await getACOptions(3), [
 | 
			
		||||
        'TECHNOLOGY, ARTS AND SCIENCES STUDIO',
 | 
			
		||||
        'SCIENCE AND TECHNOLOGY ACADEMY',
 | 
			
		||||
        'SCHOOL OF SCIENCE AND TECHNOLOGY',
 | 
			
		||||
      ]);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
      cell = await gu.getCell({section: 'References', col: 'School', rowNum: 2}).doClick();
 | 
			
		||||
      await driver.sendKeys('stuy');
 | 
			
		||||
      assert.deepEqual(await getACOptions(3), [
 | 
			
		||||
        'STUYVESANT HIGH SCHOOL',
 | 
			
		||||
        'BEDFORD STUY COLLEGIATE CHARTER SCH',
 | 
			
		||||
        'BEDFORD STUY NEW BEGINNINGS CHARTER',
 | 
			
		||||
      ]);
 | 
			
		||||
      await driver.sendKeys(Key.BACK_SPACE);
 | 
			
		||||
      assert.deepEqual(await getACOptions(3), [
 | 
			
		||||
        'STUART M TOWNSEND MIDDLE SCHOOL',
 | 
			
		||||
        'STUDIO SCHOOL (THE)',
 | 
			
		||||
        'STUYVESANT HIGH SCHOOL',
 | 
			
		||||
      ]);
 | 
			
		||||
      await driver.sendKeys(' bre');
 | 
			
		||||
      assert.equal(await driver.find('.celleditor_text_editor').value(), 'stu bre');
 | 
			
		||||
      assert.deepEqual(await getACOptions(3), [
 | 
			
		||||
        'ST BRENDAN SCHOOL',
 | 
			
		||||
        'BRONX STUDIO SCHOOL-WRITERS-ARTISTS',
 | 
			
		||||
        'BROOKLYN STUDIO SECONDARY SCHOOL',
 | 
			
		||||
      ]);
 | 
			
		||||
 | 
			
		||||
      await driver.sendKeys(Key.DOWN, Key.ENTER);
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.equal(await cell.getText(), 'ST BRENDAN SCHOOL');
 | 
			
		||||
      await gu.undo();
 | 
			
		||||
      assert.equal(await cell.getText(), '');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should highlight matching parts of items', async function() {
 | 
			
		||||
      await driver.sendKeys(Key.HOME);
 | 
			
		||||
 | 
			
		||||
      let cell = await gu.getCell({section: 'References', col: 'Color', rowNum: 2}).doClick();
 | 
			
		||||
      assert.equal(await cell.getText(), 'Red');
 | 
			
		||||
      await driver.sendKeys(Key.ENTER);
 | 
			
		||||
      await driver.findWait('.test-ref-editor-item', 1000);
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await driver.findContent('.test-ref-editor-item', /Dark Red/).findAll('span', e => e.getText()),
 | 
			
		||||
        ['Red']);
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await driver.findContent('.test-ref-editor-item', /Rebecca Purple/).findAll('span', e => e.getText()),
 | 
			
		||||
        ['Re']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      cell = await gu.getCell({section: 'References', col: 'School', rowNum: 1}).doClick();
 | 
			
		||||
      await driver.sendKeys('br tech');
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await driver.findContentWait('.test-ref-editor-item', /BROOKLYN TECH/, 1000).findAll('span', e => e.getText()),
 | 
			
		||||
        ['BR', 'TECH']);
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await driver.findContent('.test-ref-editor-item', /BUFFALO.*TECHNOLOGY/).findAll('span', e => e.getText()),
 | 
			
		||||
        ['B', 'TECH']);
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await driver.findContent('.test-ref-editor-item', /ENERGY TECH/).findAll('span', e => e.getText()),
 | 
			
		||||
        ['TECH']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should reflect changes to the target column', async function() {
 | 
			
		||||
      await driver.sendKeys(Key.HOME);
 | 
			
		||||
 | 
			
		||||
      const cell = await gu.getCell({section: 'References', col: 'Color', rowNum: 4}).doClick();
 | 
			
		||||
      assert.equal(await cell.getText(), '');
 | 
			
		||||
      await driver.sendKeys(Key.ENTER);
 | 
			
		||||
      assert.deepEqual(await getACOptions(2), ['Alice Blue', 'Añil']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      // Change a color
 | 
			
		||||
      await gu.getCell({section: 'Colors', col: 'Color Name', rowNum: 1}).doClick();
 | 
			
		||||
      await driver.sendKeys('HAZELNUT', Key.ENTER);
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // See that the old value is gone from the autocomplete, and the new one is present.
 | 
			
		||||
      await cell.click();
 | 
			
		||||
      await driver.sendKeys(Key.ENTER);
 | 
			
		||||
      assert.deepEqual(await getACOptions(2), ['Añil', 'Aqua']);
 | 
			
		||||
      await driver.sendKeys('H');
 | 
			
		||||
      assert.deepEqual(await getACOptions(2), ['HAZELNUT', 'Honeydew']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      // Delete a row.
 | 
			
		||||
      await gu.getCell({section: 'Colors', col: 'Color Name', rowNum: 1}).doClick();
 | 
			
		||||
      await driver.find('body').sendKeys(Key.chord(await gu.modKey(), '-'));
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // See that the value is gone from the autocomplete.
 | 
			
		||||
      await cell.click();
 | 
			
		||||
      await driver.sendKeys('H');
 | 
			
		||||
      assert.deepEqual(await getACOptions(2), ['Honeydew', 'Hot Pink']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      // Add a row.
 | 
			
		||||
      await gu.getCell({section: 'Colors', col: 'Color Name', rowNum: 1}).doClick();
 | 
			
		||||
      await driver.find('body').sendKeys(Key.chord(await gu.modKey(), '='));
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      await driver.sendKeys('HELIOTROPE', Key.ENTER);
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // See that the new value is visible in the autocomplete.
 | 
			
		||||
      await cell.click();
 | 
			
		||||
      await driver.sendKeys('H');
 | 
			
		||||
      assert.deepEqual(await getACOptions(2), ['HELIOTROPE', 'Honeydew']);
 | 
			
		||||
      await driver.sendKeys(Key.BACK_SPACE);
 | 
			
		||||
      assert.deepEqual(await getACOptions(2), ['Añil', 'Aqua']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      // Undo all the changes.
 | 
			
		||||
      await gu.undo(4);
 | 
			
		||||
 | 
			
		||||
      await cell.click();
 | 
			
		||||
      await driver.sendKeys('H');
 | 
			
		||||
      assert.deepEqual(await getACOptions(2), ['Honeydew', 'Hot Pink']);
 | 
			
		||||
      await driver.sendKeys(Key.BACK_SPACE);
 | 
			
		||||
      assert.deepEqual(await getACOptions(2), ['Alice Blue', 'Añil']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										862
									
								
								test/nbrowser/ReferenceList.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										862
									
								
								test/nbrowser/ReferenceList.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,862 @@
 | 
			
		||||
import {assert, driver, Key, stackWrapFunc} from 'mocha-webdriver';
 | 
			
		||||
import * as gu from 'test/nbrowser/gristUtils';
 | 
			
		||||
import {server, setupTestSuite} from 'test/nbrowser/testUtils';
 | 
			
		||||
import {Session} from 'test/nbrowser/gristUtils';
 | 
			
		||||
 | 
			
		||||
describe('ReferenceList', function() {
 | 
			
		||||
  this.timeout(20000);
 | 
			
		||||
  setupTestSuite();
 | 
			
		||||
  let session: Session;
 | 
			
		||||
  const cleanup = setupTestSuite({team: true});
 | 
			
		||||
 | 
			
		||||
  before(async function() {
 | 
			
		||||
    session = await gu.session().teamSite.login();
 | 
			
		||||
    await session.tempDoc(cleanup, 'Favorite_Films.grist');
 | 
			
		||||
 | 
			
		||||
    await gu.toggleSidePanel('right');
 | 
			
		||||
    await driver.find('.test-config-data').click();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('transforms', function() {
 | 
			
		||||
    afterEach(() => gu.checkForErrors());
 | 
			
		||||
 | 
			
		||||
    it('should correctly transform references to reference lists', async function() {
 | 
			
		||||
      // Open the Friends page.
 | 
			
		||||
      await driver.findContentWait('.test-treeview-itemHeader', /Friends/, 2000).click();
 | 
			
		||||
      await gu.waitForDocToLoad();
 | 
			
		||||
 | 
			
		||||
      // Change the column type of Favorite Film to Reference List.
 | 
			
		||||
      await gu.getCell({col: 'Favorite Film', rowNum: 1}).doClick();
 | 
			
		||||
      await gu.setType(/Reference List/);
 | 
			
		||||
 | 
			
		||||
      // Check that the column preview shows valid reference lists.
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await gu.getVisibleGridCells('Favorite Film', [1, 2, 3, 4, 5, 6, 7]),
 | 
			
		||||
        [
 | 
			
		||||
          'Forrest Gump',
 | 
			
		||||
          'Toy Story',
 | 
			
		||||
          'Avatar',
 | 
			
		||||
          'The Dark Knight',
 | 
			
		||||
          'Forrest Gump',
 | 
			
		||||
          'Alien',
 | 
			
		||||
          ''
 | 
			
		||||
        ]
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      // Apply the conversion.
 | 
			
		||||
      await driver.findContent('.type_transform_prompt button', /Apply/).click();
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // Check that Favorite Film now contains reference lists of length 1.
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await gu.getVisibleGridCells('Favorite Film', [1, 2, 3, 4, 5, 6, 7]),
 | 
			
		||||
        [
 | 
			
		||||
          'Forrest Gump',
 | 
			
		||||
          'Toy Story',
 | 
			
		||||
          'Avatar',
 | 
			
		||||
          'The Dark Knight',
 | 
			
		||||
          'Forrest Gump',
 | 
			
		||||
          'Alien',
 | 
			
		||||
          ''
 | 
			
		||||
        ]
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('rendering', function() {
 | 
			
		||||
    afterEach(() => gu.checkForErrors());
 | 
			
		||||
 | 
			
		||||
    it('should reflect the current values from the referenced column', async function() {
 | 
			
		||||
      // Open the All page.
 | 
			
		||||
      await driver.findContentWait('.test-treeview-itemHeader', /All/, 2000).click();
 | 
			
		||||
      await gu.waitForDocToLoad();
 | 
			
		||||
 | 
			
		||||
      // Add additional favorite films to a few rows in Friends.
 | 
			
		||||
      await gu.getCell('Favorite Film', 1, 'Friends record').doClick();
 | 
			
		||||
      await gu.sendKeys(Key.ENTER, 'Alien', Key.ENTER, Key.ENTER);
 | 
			
		||||
      await gu.sendKeys(Key.ENTER, 'Avatar', Key.ENTER, 'The Avengers', Key.ENTER, Key.ENTER);
 | 
			
		||||
      await gu.sendKeys(Key.ARROW_DOWN, Key.ENTER, 'The Avengers', Key.ENTER, Key.ENTER);
 | 
			
		||||
 | 
			
		||||
      // Check that the cells are rendered correctly.
 | 
			
		||||
      assert.deepEqual(await gu.getVisibleGridCells('Favorite Film', [1, 2, 3, 4, 5, 6]),
 | 
			
		||||
        [
 | 
			
		||||
          'Forrest Gump\nAlien',
 | 
			
		||||
          'Toy Story\nAvatar\nThe Avengers',
 | 
			
		||||
          'Avatar',
 | 
			
		||||
          'The Dark Knight\nThe Avengers',
 | 
			
		||||
          'Forrest Gump',
 | 
			
		||||
          'Alien'
 | 
			
		||||
        ]
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      // Change a few of the film titles.
 | 
			
		||||
      await gu.getCell('Title', 1, 'Films record').doClick();
 | 
			
		||||
      await gu.sendKeys('Toy Story 2', Key.ENTER);
 | 
			
		||||
      await gu.sendKeys(Key.ARROW_DOWN, 'Aliens', Key.ENTER);
 | 
			
		||||
      await gu.sendKeys(Key.ARROW_DOWN, 'The Dark Knight Rises', Key.ENTER);
 | 
			
		||||
 | 
			
		||||
      // Check that the Favorite Film column reflects the new titles.
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await gu.getVisibleGridCells('Favorite Film', [1, 2, 3, 4, 5, 6], 'Friends record'),
 | 
			
		||||
        [
 | 
			
		||||
          'Forrest Gump\nAliens',
 | 
			
		||||
          'Toy Story 2\nAvatar\nThe Avengers',
 | 
			
		||||
          'Avatar',
 | 
			
		||||
          'The Dark Knight Rises\nThe Avengers',
 | 
			
		||||
          'Forrest Gump',
 | 
			
		||||
          'Aliens'
 | 
			
		||||
        ]
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it(`should show '[Blank]' if the referenced item is blank`, async function() {
 | 
			
		||||
      // Clear the cell in Films record containing Avatar.
 | 
			
		||||
      await gu.getCell('Title', 4, 'Films record').doClick();
 | 
			
		||||
      await gu.sendKeys(Key.BACK_SPACE);
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // Check that all references to Avatar now show '[Blank]'.
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await gu.getVisibleGridCells('Favorite Film', [1, 2, 3, 4, 5, 6], 'Friends record'),
 | 
			
		||||
        [
 | 
			
		||||
          'Forrest Gump\nAliens',
 | 
			
		||||
          'Toy Story 2\n[Blank]\nThe Avengers',
 | 
			
		||||
          '[Blank]',
 | 
			
		||||
          'The Dark Knight Rises\nThe Avengers',
 | 
			
		||||
          'Forrest Gump',
 | 
			
		||||
          'Aliens'
 | 
			
		||||
        ]
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      // Check that a '[Blank]' token is shown when the reference list editor is open.
 | 
			
		||||
      await gu.getCell('Favorite Film', 2, 'Friends record').doClick();
 | 
			
		||||
      await gu.sendKeys(Key.ENTER);
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await driver.findAll('.cell_editor .test-tokenfield .test-tokenfield-token', el => el.getText()),
 | 
			
		||||
        ['Toy Story 2', '[Blank]', 'The Avengers']
 | 
			
		||||
      );
 | 
			
		||||
      await gu.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      // Undo, and check that it shows Avatar again.
 | 
			
		||||
      await gu.undo();
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await gu.getVisibleGridCells('Favorite Film', [1, 2, 3, 4, 5, 6], 'Friends record'),
 | 
			
		||||
        [
 | 
			
		||||
          'Forrest Gump\nAliens',
 | 
			
		||||
          'Toy Story 2\nAvatar\nThe Avengers',
 | 
			
		||||
          'Avatar',
 | 
			
		||||
          'The Dark Knight Rises\nThe Avengers',
 | 
			
		||||
          'Forrest Gump',
 | 
			
		||||
          'Aliens'
 | 
			
		||||
        ]
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      // Now delete the row containing Avatar.
 | 
			
		||||
      await gu.getCell('Title', 4, 'Films record').doClick();
 | 
			
		||||
      await gu.sendKeys(Key.chord(await gu.modKey(), '-'));
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // Check that all references to Avatar are deleted.
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await gu.getVisibleGridCells('Favorite Film', [1, 2, 3, 4, 5, 6], 'Friends record'),
 | 
			
		||||
        [
 | 
			
		||||
          'Forrest Gump\nAliens',
 | 
			
		||||
          'Toy Story 2\nThe Avengers',
 | 
			
		||||
          '',
 | 
			
		||||
          'The Dark Knight Rises\nThe Avengers',
 | 
			
		||||
          'Forrest Gump',
 | 
			
		||||
          'Aliens'
 | 
			
		||||
        ]
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      await gu.undo();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should still work after renaming visible column', async function() {
 | 
			
		||||
      // Check that we have a Ref:Films column displaying Title.
 | 
			
		||||
      await gu.getCell({section: 'Friends record', col: 'Favorite Film', rowNum: 2}).doClick();
 | 
			
		||||
      assert.equal(await driver.find('.test-fbuilder-ref-table-select .test-select-row').getText(), 'Films');
 | 
			
		||||
      assert.equal(await driver.find('.test-fbuilder-ref-col-select .test-select-row').getText(), 'Title');
 | 
			
		||||
 | 
			
		||||
      // Rename the Title column in Films, to TitleX.
 | 
			
		||||
      // In browser tests, first record is hidden, we need to scroll first.
 | 
			
		||||
      await gu.selectSectionByTitle('Films record');
 | 
			
		||||
      await gu.scrollActiveView(0, -100);
 | 
			
		||||
      await gu.getCell({section: 'Films record', col: 'Title', rowNum: 1}).doClick();
 | 
			
		||||
      await driver.find('.test-field-label').click();
 | 
			
		||||
      await gu.sendKeys(await gu.selectAllKey(), 'TitleX', Key.ENTER);
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // Check that the Ref:Films column shows TitleX and is still correct.
 | 
			
		||||
      await gu.getCell({section: 'Friends record', col: 'Favorite Film', rowNum: 2}).doClick();
 | 
			
		||||
      await driver.find('.test-fbuilder-ref-table-select').click();
 | 
			
		||||
      assert.equal(await driver.find('.test-fbuilder-ref-table-select .test-select-row').getText(), 'Films');
 | 
			
		||||
      assert.equal(await driver.find('.test-fbuilder-ref-col-select .test-select-row').getText(), 'TitleX');
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await gu.getVisibleGridCells('Favorite Film', [1, 2, 3, 4, 5, 6]),
 | 
			
		||||
        [
 | 
			
		||||
          'Forrest Gump\nAliens',
 | 
			
		||||
          'Toy Story 2\nAvatar\nThe Avengers',
 | 
			
		||||
          'Avatar',
 | 
			
		||||
          'The Dark Knight Rises\nThe Avengers',
 | 
			
		||||
          'Forrest Gump',
 | 
			
		||||
          'Aliens'
 | 
			
		||||
        ]
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      // Undo and verify again.
 | 
			
		||||
      await gu.undo();
 | 
			
		||||
      await gu.getCell({section: 'Friends record', col: 'Favorite Film', rowNum: 2}).doClick();
 | 
			
		||||
      assert.equal(await driver.find('.test-fbuilder-ref-col-select .test-select-row').getText(), 'Title');
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await gu.getVisibleGridCells('Favorite Film', [1, 2, 3, 4, 5, 6]),
 | 
			
		||||
        [
 | 
			
		||||
          'Forrest Gump\nAliens',
 | 
			
		||||
          'Toy Story 2\nAvatar\nThe Avengers',
 | 
			
		||||
          'Avatar',
 | 
			
		||||
          'The Dark Knight Rises\nThe Avengers',
 | 
			
		||||
          'Forrest Gump',
 | 
			
		||||
          'Aliens'
 | 
			
		||||
        ]
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should switch to rowId if the selected visible column is deleted', async function() {
 | 
			
		||||
      // Delete the Title column from Films.
 | 
			
		||||
      await gu.getCell({section: 'Films record', col: 'Title', rowNum: 1}).doClick();
 | 
			
		||||
      await gu.sendKeys(Key.chord(Key.ALT, '-'));
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // Check that Favorite Film switched to showing RowID.
 | 
			
		||||
      await gu.getCell({section: 'Friends record', col: 'Favorite Film', rowNum: 2}).doClick();
 | 
			
		||||
      assert.equal(await driver.find('.test-fbuilder-ref-table-select .test-select-row').getText(), 'Films');
 | 
			
		||||
      assert.equal(await driver.find('.test-fbuilder-ref-col-select .test-select-row').getText(), 'Row ID');
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await gu.getVisibleGridCells('Favorite Film', [1, 2, 3, 4, 5, 6]),
 | 
			
		||||
        [
 | 
			
		||||
          'Films[2]\nFilms[3]',
 | 
			
		||||
          'Films[1]\nFilms[4]\nFilms[6]',
 | 
			
		||||
          'Films[4]',
 | 
			
		||||
          'Films[5]\nFilms[6]',
 | 
			
		||||
          'Films[2]',
 | 
			
		||||
          'Films[3]'
 | 
			
		||||
        ]
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      await gu.undo();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should render Row ID values as TableId[RowId]', async function() {
 | 
			
		||||
      await driver.findContentWait('.test-treeview-itemHeader', /Friends/, 2000).click();
 | 
			
		||||
      await gu.waitForDocToLoad();
 | 
			
		||||
 | 
			
		||||
      // Create a new Reference List column.
 | 
			
		||||
      await driver.find('.test-right-tab-field').click();
 | 
			
		||||
      await driver.find('.mod-add-column').click();
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      await gu.setType(/Reference List/);
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // Populate the first few rows of the new column with some references.
 | 
			
		||||
      await gu.getCell({rowNum: 1, col: 'A'}).click();
 | 
			
		||||
      await driver.sendKeys('1', Key.ENTER, '2', Key.ENTER, Key.ENTER);
 | 
			
		||||
      await driver.sendKeys('2', Key.ENTER, Key.ENTER);
 | 
			
		||||
      await driver.sendKeys('3', Key.ENTER, '4', Key.ENTER, '5', Key.ENTER, Key.ENTER);
 | 
			
		||||
 | 
			
		||||
      // Check that the cells render their tokens as TableId[RowId].
 | 
			
		||||
      assert.deepEqual(await gu.getVisibleGridCells(3, [1, 2, 3, 4, 5, 6]),
 | 
			
		||||
        ['Friends[1]\nFriends[2]', 'Friends[2]', 'Friends[3]\nFriends[4]\nFriends[5]', '', '', '']);
 | 
			
		||||
 | 
			
		||||
      // Check that switching Shown Column to Name works correctly.
 | 
			
		||||
      await driver.find('.test-fbuilder-ref-col-select').click();
 | 
			
		||||
      await driver.findContent('.test-select-row', /Name/).click();
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.deepEqual(await gu.getVisibleGridCells(3, [1, 2, 3, 4, 5, 6]),
 | 
			
		||||
        ['Roger\nTom', 'Tom', 'Sydney\nBill\nEvan', '', '', '']);
 | 
			
		||||
 | 
			
		||||
      // Add a new reference.
 | 
			
		||||
      await gu.getCell(3, 5).click();
 | 
			
		||||
      await driver.sendKeys('Roger');
 | 
			
		||||
      await driver.sendKeys(Key.ENTER, Key.ENTER);
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // Check that switching between Row ID and Name still works correctly.
 | 
			
		||||
      assert.deepEqual(await gu.getVisibleGridCells(3, [1, 2, 3, 4, 5, 6]),
 | 
			
		||||
        ['Roger\nTom', 'Tom', 'Sydney\nBill\nEvan', '', 'Roger', '']);
 | 
			
		||||
      await driver.find('.test-fbuilder-ref-col-select').click();
 | 
			
		||||
      await driver.findContent('.test-select-row', /Row ID/).click();
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.deepEqual(await gu.getVisibleGridCells(3, [1, 2, 3, 4, 5, 6]),
 | 
			
		||||
        ['Friends[1]\nFriends[2]', 'Friends[2]', 'Friends[3]\nFriends[4]\nFriends[5]', '', 'Friends[1]', '']);
 | 
			
		||||
      await driver.find('.test-fbuilder-ref-col-select').click();
 | 
			
		||||
      await driver.findContent('.test-select-row', /Name/).click();
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.deepEqual(await gu.getVisibleGridCells(3, [1, 2, 3, 4, 5, 6]),
 | 
			
		||||
        ['Roger\nTom', 'Tom', 'Sydney\nBill\nEvan', '', 'Roger', '']);
 | 
			
		||||
 | 
			
		||||
      await gu.undo();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should allow entering numeric id before target table is loaded', async function() {
 | 
			
		||||
      // Refresh the document.
 | 
			
		||||
      await driver.navigate().refresh();
 | 
			
		||||
      await gu.waitForDocToLoad();
 | 
			
		||||
 | 
			
		||||
      // Now pause the server.
 | 
			
		||||
      const cell = gu.getCell({col: 'A', rowNum: 1});
 | 
			
		||||
      await server.pauseUntil(async () => {
 | 
			
		||||
        assert.equal(await cell.getText(), 'Friends[1]\nFriends[2]');
 | 
			
		||||
        await cell.click();
 | 
			
		||||
        await gu.sendKeys('5');
 | 
			
		||||
        // Check that the autocomplete has no items yet.
 | 
			
		||||
        assert.isEmpty(await driver.findAll('.test-autocomplete .test-ref-editor-new-item'));
 | 
			
		||||
        await gu.sendKeys(Key.ENTER, Key.ENTER);
 | 
			
		||||
      });
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.equal(await cell.getText(), 'Friends[5]');
 | 
			
		||||
 | 
			
		||||
      await gu.undo();
 | 
			
		||||
      assert.equal(await cell.getText(), 'Friends[1]\nFriends[2]');
 | 
			
		||||
 | 
			
		||||
      // Once server is responsive, a valid value should not offer a "new item".
 | 
			
		||||
      await cell.click();
 | 
			
		||||
      await gu.sendKeys('5');
 | 
			
		||||
      await driver.findWait('.test-ref-editor-item', 500);
 | 
			
		||||
      assert.isFalse(await driver.find('.test-ref-editor-new-item').isPresent());
 | 
			
		||||
      await gu.sendKeys(Key.ENTER, Key.ENTER);
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.equal(await cell.getText(), 'Friends[5]');
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('sorting', function() {
 | 
			
		||||
    afterEach(() => gu.checkForErrors());
 | 
			
		||||
 | 
			
		||||
    it('should sort by the display values of the referenced column', async function() {
 | 
			
		||||
      this.timeout(10000);
 | 
			
		||||
      await driver.findContentWait('.test-treeview-itemHeader', /All/, 2000).click();
 | 
			
		||||
      await gu.waitForDocToLoad();
 | 
			
		||||
      await gu.getCell('Favorite Film', 1, 'Friends record').doClick();
 | 
			
		||||
 | 
			
		||||
      await driver.find('.test-right-tab-pagewidget').click();
 | 
			
		||||
      await driver.find('.test-config-sortAndFilter').click();
 | 
			
		||||
 | 
			
		||||
      // Sort the Favorite Film column.
 | 
			
		||||
      await driver.find('.test-vconfigtab-sort-add').click();
 | 
			
		||||
      await driver.findContent('.test-vconfigtab-sort-add-menu-row', /Favorite_Film/).click();
 | 
			
		||||
      await driver.find('.test-vconfigtab-sort-save').click();
 | 
			
		||||
 | 
			
		||||
      // Check that the records are sorted by display value.
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await gu.getVisibleGridCells('Favorite Film', [1, 2, 3, 4, 5, 6], 'Friends record'),
 | 
			
		||||
        [
 | 
			
		||||
          'Aliens',
 | 
			
		||||
          'Avatar',
 | 
			
		||||
          'Forrest Gump',
 | 
			
		||||
          'Forrest Gump\nAliens',
 | 
			
		||||
          'The Dark Knight Rises\nThe Avengers',
 | 
			
		||||
          'Toy Story 2\nAvatar\nThe Avengers'
 | 
			
		||||
        ]
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it("should update sort when display column is changed", async function() {
 | 
			
		||||
      // Change a film title to cause the sort order to change.
 | 
			
		||||
      await gu.getCell('Title', 5, 'Films record').doClick();
 | 
			
		||||
      await gu.sendKeys('Batman Begins', Key.ENTER);
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // Check that the updated sort order is correct.
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await gu.getVisibleGridCells('Favorite Film', [1, 2, 3, 4, 5, 6], 'Friends record'),
 | 
			
		||||
        [
 | 
			
		||||
          'Aliens',
 | 
			
		||||
          'Avatar',
 | 
			
		||||
          'Batman Begins\nThe Avengers',
 | 
			
		||||
          'Forrest Gump',
 | 
			
		||||
          'Forrest Gump\nAliens',
 | 
			
		||||
          'Toy Story 2\nAvatar\nThe Avengers'
 | 
			
		||||
        ]
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      // Clear a film title to cause the sort order to change.
 | 
			
		||||
      await gu.getCell('Title', 2, 'Films record').doClick();
 | 
			
		||||
      await gu.sendKeys(Key.BACK_SPACE);
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // Check that the updated sort order is correct.
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await gu.getVisibleGridCells('Favorite Film', [1, 2, 3, 4, 5, 6], 'Friends record'),
 | 
			
		||||
        [
 | 
			
		||||
          '[Blank]',
 | 
			
		||||
          '[Blank]\nAliens',
 | 
			
		||||
          'Aliens',
 | 
			
		||||
          'Avatar',
 | 
			
		||||
          'Batman Begins\nThe Avengers',
 | 
			
		||||
          'Toy Story 2\nAvatar\nThe Avengers'
 | 
			
		||||
        ]
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      // Clear a film reference to cause the sort order to change.
 | 
			
		||||
      await gu.getCell('Favorite Film', 4, 'Friends record').doClick();
 | 
			
		||||
      await gu.sendKeys(Key.BACK_SPACE);
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // Check that the updated sort order is correct.
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await gu.getVisibleGridCells('Favorite Film', [1, 2, 3, 4, 5, 6], 'Friends record'),
 | 
			
		||||
        [
 | 
			
		||||
          '',
 | 
			
		||||
          '[Blank]',
 | 
			
		||||
          '[Blank]\nAliens',
 | 
			
		||||
          'Aliens',
 | 
			
		||||
          'Batman Begins\nThe Avengers',
 | 
			
		||||
          'Toy Story 2\nAvatar\nThe Avengers'
 | 
			
		||||
        ]
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it("should sort consistently when column contains AltText", async function() {
 | 
			
		||||
      // Enter an invalid reference in Favorite Film.
 | 
			
		||||
      await gu.getCell('Favorite Film', 4, 'Friends record').doClick();
 | 
			
		||||
      await gu.sendKeys('Aliens 4', Key.ENTER, Key.ENTER);
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // Check that the updated sort order is correct.
 | 
			
		||||
      // Accept '[u\'Aliens 4\']' as a py2 variant of '[\'Aliens 4\']'
 | 
			
		||||
      const variant = await gu.getCell('Favorite Film', 1, 'Friends record').getText();
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await gu.getVisibleGridCells('Favorite Film', [1, 2, 3, 4, 5, 6], 'Friends record'),
 | 
			
		||||
        [
 | 
			
		||||
          variant.startsWith('[u') ? '[u\'Aliens 4\']' : '[\'Aliens 4\']',
 | 
			
		||||
          '',
 | 
			
		||||
          '[Blank]',
 | 
			
		||||
          '[Blank]\nAliens',
 | 
			
		||||
          'Batman Begins\nThe Avengers',
 | 
			
		||||
          'Toy Story 2\nAvatar\nThe Avengers'
 | 
			
		||||
        ]
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('autocomplete', function() {
 | 
			
		||||
    const getACOptions = stackWrapFunc(async (limit?: number) => {
 | 
			
		||||
      await driver.findWait('.test-ref-editor-item', 1000);
 | 
			
		||||
      return (await driver.findAll('.test-ref-editor-item', el => el.getText())).slice(0, limit);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    before(async function() {
 | 
			
		||||
      await session.tempDoc(cleanup, 'Ref-List-AC-Test.grist');
 | 
			
		||||
      await gu.toggleSidePanel('right', 'close');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    afterEach(() => gu.checkForErrors());
 | 
			
		||||
 | 
			
		||||
    it('should render first items when opening empty cell', async function() {
 | 
			
		||||
      await driver.sendKeys(Key.HOME);
 | 
			
		||||
 | 
			
		||||
      let cell = await gu.getCell({section: 'References', col: 'Colors', rowNum: 4}).doClick();
 | 
			
		||||
      assert.equal(await cell.getText(), '');
 | 
			
		||||
      await driver.sendKeys(Key.ENTER);
 | 
			
		||||
      // Check the first few items.
 | 
			
		||||
      assert.deepEqual(await getACOptions(3), ["Alice Blue", "Añil", "Aqua"]);
 | 
			
		||||
      // No item is selected.
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-item.selected').isPresent(), false);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      cell = await gu.getCell({section: 'References', col: 'Schools', rowNum: 6}).doClick();
 | 
			
		||||
      assert.equal(await cell.getText(), '');
 | 
			
		||||
      await driver.sendKeys(Key.ENTER);
 | 
			
		||||
      // Check the first few items; should be sorted alphabetically.
 | 
			
		||||
      assert.deepEqual(await getACOptions(3),
 | 
			
		||||
        ["2 SCHOOL", "4 SCHOOL", "47 AMER SIGN LANG & ENG LOWER "]);
 | 
			
		||||
      // No item is selected.
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-item.selected').isPresent(), false);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should save correct item on click', async function() {
 | 
			
		||||
      await driver.sendKeys(Key.HOME);
 | 
			
		||||
 | 
			
		||||
      // Edit a cell by double-clicking.
 | 
			
		||||
      let cell = await gu.getCell({section: 'References', col: 'Colors', rowNum: 2}).doClick();
 | 
			
		||||
      await driver.withActions(a => a.doubleClick(cell));
 | 
			
		||||
 | 
			
		||||
      // Scroll to another item and click it.
 | 
			
		||||
      await gu.sendKeys('ro');
 | 
			
		||||
      let item = driver.findContent('.test-ref-editor-item', 'Rosy Brown');
 | 
			
		||||
      await gu.scrollIntoView(item);
 | 
			
		||||
      await item.click();
 | 
			
		||||
 | 
			
		||||
      // It should get added; and undo should revert adding it.
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await driver.findAll('.cell_editor .test-tokenfield .test-tokenfield-token', el => el.getText()),
 | 
			
		||||
        ['Red', 'Rosy Brown']
 | 
			
		||||
      );
 | 
			
		||||
      await gu.sendKeys(Key.chord(await gu.modKey(), 'z'));
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await driver.findAll('.cell_editor .test-tokenfield .test-tokenfield-token', el => el.getText()),
 | 
			
		||||
        ['Red']
 | 
			
		||||
      );
 | 
			
		||||
      await gu.sendKeys(Key.ESCAPE);
 | 
			
		||||
      assert.equal(await cell.getText(), 'Red');
 | 
			
		||||
 | 
			
		||||
      // Edit another cell by starting to type.
 | 
			
		||||
      cell = await gu.getCell({section: 'References', col: 'Colors', rowNum: 4}).doClick();
 | 
			
		||||
      await driver.sendKeys("gr");
 | 
			
		||||
      await driver.findWait('.test-ref-editor-item', 1000);
 | 
			
		||||
      item = driver.findContent('.test-ref-editor-item', 'Medium Sea Green');
 | 
			
		||||
      await gu.scrollIntoView(item);
 | 
			
		||||
      await item.click();
 | 
			
		||||
      await gu.sendKeys(Key.ENTER);
 | 
			
		||||
 | 
			
		||||
      // It should get saved; and undo should restore the previous value.
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.equal(await cell.getText(), 'Medium Sea Green');
 | 
			
		||||
      await gu.undo();
 | 
			
		||||
      assert.equal(await cell.getText(), '');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should save correct item after selecting with arrow keys', async function() {
 | 
			
		||||
      // Same as the previous test, but instead of clicking items, select item using arrow keys.
 | 
			
		||||
 | 
			
		||||
      // Edit a cell by double-clicking.
 | 
			
		||||
      let cell = await gu.getCell({section: 'References', col: 'Colors', rowNum: 2}).doClick();
 | 
			
		||||
      await driver.withActions(a => a.doubleClick(cell));
 | 
			
		||||
 | 
			
		||||
      // Move to another item and hit Enter
 | 
			
		||||
      await gu.sendKeys('pa');
 | 
			
		||||
      await driver.sendKeys(Key.DOWN, Key.DOWN, Key.DOWN);
 | 
			
		||||
      assert.equal(await driver.findWait('.test-ref-editor-item.selected', 1000).getText(), 'Pale Violet Red');
 | 
			
		||||
      await driver.sendKeys(Key.ENTER);
 | 
			
		||||
 | 
			
		||||
      // It should get added; and undo should revert adding it.
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await driver.findAll('.cell_editor .test-tokenfield .test-tokenfield-token', el => el.getText()),
 | 
			
		||||
        ['Red', 'Pale Violet Red']
 | 
			
		||||
      );
 | 
			
		||||
      await gu.sendKeys(Key.chord(await gu.modKey(), 'z'));
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await driver.findAll('.cell_editor .test-tokenfield .test-tokenfield-token', el => el.getText()),
 | 
			
		||||
        ['Red']
 | 
			
		||||
      );
 | 
			
		||||
      await gu.sendKeys(Key.ESCAPE);
 | 
			
		||||
      assert.equal(await cell.getText(), 'Red');
 | 
			
		||||
 | 
			
		||||
      // Edit another cell by starting to type.
 | 
			
		||||
      cell = await gu.getCell({section: 'References', col: 'Colors', rowNum: 4}).doClick();
 | 
			
		||||
      await driver.sendKeys("gr");
 | 
			
		||||
      await driver.findWait('.test-ref-editor-item', 1000);
 | 
			
		||||
      await driver.sendKeys(Key.UP, Key.UP, Key.UP, Key.UP, Key.UP);
 | 
			
		||||
      assert.equal(await driver.findWait('.test-ref-editor-item.selected', 1000).getText(), 'Chocolate');
 | 
			
		||||
      await driver.sendKeys(Key.ENTER, Key.ENTER);
 | 
			
		||||
 | 
			
		||||
      // It should get saved; and undo should restore the previous value.
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.equal(await cell.getText(), 'Chocolate');
 | 
			
		||||
      await gu.undo();
 | 
			
		||||
      assert.equal(await cell.getText(), '');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should return to text-as-typed when nothing is selected', async function() {
 | 
			
		||||
      const cell = await gu.getCell({section: 'References', col: 'Colors', rowNum: 2}).doClick();
 | 
			
		||||
      await driver.sendKeys("da");
 | 
			
		||||
      assert.deepEqual(await getACOptions(2), ["Dark Blue", "Dark Cyan"]);
 | 
			
		||||
 | 
			
		||||
      // Check that the first item is highlighted by default.
 | 
			
		||||
      assert.equal(await driver.find('.cell_editor .test-tokenfield .test-tokenfield-input').value(), 'da');
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-item.selected').getText(), 'Dark Blue');
 | 
			
		||||
 | 
			
		||||
      // Select second item. Both the textbox and the dropdown show the selection.
 | 
			
		||||
      await driver.sendKeys(Key.DOWN);
 | 
			
		||||
      assert.equal(await driver.find('.cell_editor .test-tokenfield .test-tokenfield-input').value(), 'Dark Cyan');
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-item.selected').getText(), 'Dark Cyan');
 | 
			
		||||
 | 
			
		||||
      // Move back to no-selection state.
 | 
			
		||||
      await driver.sendKeys(Key.UP, Key.UP);
 | 
			
		||||
      assert.equal(await driver.find('.cell_editor .test-tokenfield .test-tokenfield-input').value(), 'da');
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-item.selected').isPresent(), false);
 | 
			
		||||
 | 
			
		||||
      // Mouse over an item.
 | 
			
		||||
      await driver.findContent('.test-ref-editor-item', /Dark Gray/).mouseMove();
 | 
			
		||||
      assert.equal(await driver.find('.cell_editor .test-tokenfield .test-tokenfield-input').value(), 'Dark Gray');
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-item.selected').getText(), 'Dark Gray');
 | 
			
		||||
 | 
			
		||||
      // Mouse back out of the dropdown
 | 
			
		||||
      await driver.find('.cell_editor .test-tokenfield .test-tokenfield-input').mouseMove();
 | 
			
		||||
      assert.equal(await driver.find('.cell_editor .test-tokenfield .test-tokenfield-input').value(), 'da');
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-item.selected').isPresent(), false);
 | 
			
		||||
 | 
			
		||||
      // Click away and check the cell is now empty since no reference items were added.
 | 
			
		||||
      await gu.getCell({section: 'References', col: 'Colors', rowNum: 1}).doClick();
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.equal(await cell.getText(), "");
 | 
			
		||||
      assert.equal(await cell.find('.field_clip').matches('.invalid'), false);
 | 
			
		||||
 | 
			
		||||
      await gu.undo();
 | 
			
		||||
      assert.equal(await cell.getText(), "Red");
 | 
			
		||||
      assert.equal(await cell.find('.field_clip').matches('.invalid'), false);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should save text as typed when nothing is selected', async function() {
 | 
			
		||||
      const cell = await gu.getCell({section: 'References', col: 'Colors', rowNum: 1}).doClick();
 | 
			
		||||
      await driver.sendKeys("lavender ", Key.ENTER, Key.ENTER);
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.equal(await cell.getText(), "Lavender");
 | 
			
		||||
      await gu.undo();
 | 
			
		||||
      assert.equal(await cell.getText(), "Dark Slate Blue");
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should offer an add-new option when no good match', async function() {
 | 
			
		||||
      const cell = await gu.getCell({section: 'References', col: 'Colors', rowNum: 2}).doClick();
 | 
			
		||||
      await driver.sendKeys("pinkish");
 | 
			
		||||
      // There are inexact matches.
 | 
			
		||||
      assert.deepEqual(await getACOptions(3),
 | 
			
		||||
        ["Pink", "Deep Pink", "Hot Pink"]);
 | 
			
		||||
      // Nothing is selected, and the "add new" item is present.
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-item.selected').isPresent(), false);
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-new-item').getText(), "pinkish");
 | 
			
		||||
 | 
			
		||||
      // Click the "add new" item. The new value should be added, and should not appear invalid.
 | 
			
		||||
      await driver.find('.test-ref-editor-new-item').click();
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await driver.findAll('.cell_editor .test-tokenfield .test-tokenfield-token', el => el.getText()),
 | 
			
		||||
        ['pinkish']
 | 
			
		||||
      );
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await driver.findAll(
 | 
			
		||||
          '.cell_editor .test-tokenfield .test-tokenfield-token',
 | 
			
		||||
          el => el.matches('[class*=-invalid]')
 | 
			
		||||
        ),
 | 
			
		||||
        [false]
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      // Add another new item (with the keyboard), and check that it also appears correctly.
 | 
			
		||||
      await driver.sendKeys("almost pink", Key.ARROW_UP, Key.ENTER);
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await driver.findAll('.cell_editor .test-tokenfield .test-tokenfield-token', el => el.getText()),
 | 
			
		||||
        ['pinkish', 'almost pink']
 | 
			
		||||
      );
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await driver.findAll(
 | 
			
		||||
          '.cell_editor .test-tokenfield .test-tokenfield-token',
 | 
			
		||||
          el => el.matches('[class*=-invalid]')
 | 
			
		||||
        ),
 | 
			
		||||
        [false, false]
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      // Save the changes to the cell.
 | 
			
		||||
      await gu.sendKeys(Key.ENTER);
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.equal(await cell.getText(), "pinkish\nalmost pink");
 | 
			
		||||
 | 
			
		||||
      // Check that the referenced table now has "pinkish" and "almost pink".
 | 
			
		||||
      await driver.findContentWait('.test-treeview-itemHeader', /Colors/, 2000).click();
 | 
			
		||||
      await gu.waitForDocToLoad();
 | 
			
		||||
      await gu.sendKeys(Key.chord(await gu.modKey(), Key.ARROW_DOWN));
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await gu.getVisibleGridCells('Color Name', [146, 147]),
 | 
			
		||||
        ['pinkish', 'almost pink']
 | 
			
		||||
      );
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await gu.getVisibleGridCells('C2', [146, 147]),
 | 
			
		||||
        ['pinkish', 'almost pink']
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      // Requires 2 undos, because adding the "pinkish" and "almost pink" records is a separate action. TODO these
 | 
			
		||||
      // actions should be bundled.
 | 
			
		||||
      await gu.undo(2);
 | 
			
		||||
      assert.equal(await gu.getCell({section: 'References', col: 'Colors', rowNum: 2}).getText(), 'Red');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should not offer an add-new option when target is a formula', async function() {
 | 
			
		||||
      // Click on an alt-text cell.
 | 
			
		||||
      const cell = await gu.getCell({section: 'References', col: 'Colors', rowNum: 3}).doClick();
 | 
			
		||||
      assert.equal(await cell.getText(), "hello");
 | 
			
		||||
      assert.equal(await cell.find('.field_clip').matches('.invalid'), true);
 | 
			
		||||
 | 
			
		||||
      await driver.sendKeys(Key.ENTER, 'hello');
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-new-item').getText(), "hello");
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      // Change the visible column to the formula column "C2".
 | 
			
		||||
      await gu.toggleSidePanel('right', 'open');
 | 
			
		||||
      await driver.find('.test-right-tab-field').click();
 | 
			
		||||
      await driver.find('.test-fbuilder-ref-col-select').click();
 | 
			
		||||
      await driver.findContent('.test-select-row', /C2/).click();
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // Check that for the same cell, the dropdown no longer has an "add new" option.
 | 
			
		||||
      await cell.click();
 | 
			
		||||
      await driver.sendKeys(Key.ENTER, 'hello');
 | 
			
		||||
      await driver.findWait('.test-ref-editor-item', 1000);
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-item.selected').isPresent(), false);
 | 
			
		||||
      assert.equal(await driver.find('.test-ref-editor-new-item').isPresent(), false);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      await gu.undo();
 | 
			
		||||
      await gu.toggleSidePanel('right', 'close');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should offer items ordered by best match', async function() {
 | 
			
		||||
      let cell = await gu.getCell({section: 'References', col: 'Colors', rowNum: 1}).doClick();
 | 
			
		||||
      assert.equal(await cell.getText(), 'Dark Slate Blue');
 | 
			
		||||
      await driver.sendKeys(Key.ENTER, 'Dark Slate Blue');
 | 
			
		||||
      assert.deepEqual(await getACOptions(4),
 | 
			
		||||
        ['Dark Slate Blue', 'Dark Slate Gray', 'Slate Blue', 'Medium Slate Blue']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      await driver.sendKeys('blac');
 | 
			
		||||
      assert.deepEqual(await getACOptions(6),
 | 
			
		||||
        ['Black', 'Blanched Almond', 'Blue', 'Blue Violet', 'Alice Blue', 'Cadet Blue']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      cell = await gu.getCell({section: 'References', col: 'Colors', rowNum: 3}).doClick();
 | 
			
		||||
      assert.equal(await cell.getText(), 'hello');    // Alt-text
 | 
			
		||||
      await driver.sendKeys('hello');
 | 
			
		||||
      assert.deepEqual(await getACOptions(2),
 | 
			
		||||
        ['Honeydew', 'Hot Pink']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      cell = await gu.getCell({section: 'References', col: 'ColorCodes', rowNum: 2}).doClick();
 | 
			
		||||
      assert.equal(await cell.getText(), '#808080');
 | 
			
		||||
      await driver.sendKeys('#808080');
 | 
			
		||||
      assert.deepEqual(await getACOptions(5),
 | 
			
		||||
        ['#808080', '#808000', '#800000', '#800080', '#87CEEB']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      cell = await gu.getCell({section: 'References', col: 'XNums', rowNum: 2}).doClick();
 | 
			
		||||
      assert.equal(await cell.getText(), '2019-04-29');
 | 
			
		||||
      await driver.sendKeys('2019-04-29');
 | 
			
		||||
      assert.deepEqual(await getACOptions(4),
 | 
			
		||||
        ['2019-04-29', '2020-04-29', '2019-11-05', '2020-04-28']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should update choices as user types into textbox', async function() {
 | 
			
		||||
      let cell = await gu.getCell({section: 'References', col: 'Schools', rowNum: 1}).doClick();
 | 
			
		||||
      assert.equal(await cell.getText(), 'TECHNOLOGY, ARTS AND SCIENCES STUDIO');
 | 
			
		||||
      await driver.sendKeys('TECHNOLOGY, ARTS AND SCIENCES STUDIO');
 | 
			
		||||
      assert.deepEqual(await getACOptions(3), [
 | 
			
		||||
        'TECHNOLOGY, ARTS AND SCIENCES STUDIO',
 | 
			
		||||
        'SCIENCE AND TECHNOLOGY ACADEMY',
 | 
			
		||||
        'SCHOOL OF SCIENCE AND TECHNOLOGY',
 | 
			
		||||
      ]);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
      cell = await gu.getCell({section: 'References', col: 'Schools', rowNum: 2}).doClick();
 | 
			
		||||
      await driver.sendKeys('stuy');
 | 
			
		||||
      assert.deepEqual(await getACOptions(3), [
 | 
			
		||||
        'STUYVESANT HIGH SCHOOL',
 | 
			
		||||
        'BEDFORD STUY COLLEGIATE CHARTER SCH',
 | 
			
		||||
        'BEDFORD STUY NEW BEGINNINGS CHARTER',
 | 
			
		||||
      ]);
 | 
			
		||||
      await driver.sendKeys(Key.BACK_SPACE);
 | 
			
		||||
      assert.deepEqual(await getACOptions(3), [
 | 
			
		||||
        'STUART M TOWNSEND MIDDLE SCHOOL',
 | 
			
		||||
        'STUDIO SCHOOL (THE)',
 | 
			
		||||
        'STUYVESANT HIGH SCHOOL',
 | 
			
		||||
      ]);
 | 
			
		||||
      await driver.sendKeys(' bre');
 | 
			
		||||
      assert.equal(await driver.find('.cell_editor .test-tokenfield .test-tokenfield-input').value(), 'stu bre');
 | 
			
		||||
      assert.deepEqual(await getACOptions(3), [
 | 
			
		||||
        'ST BRENDAN SCHOOL',
 | 
			
		||||
        'BRONX STUDIO SCHOOL-WRITERS-ARTISTS',
 | 
			
		||||
        'BROOKLYN STUDIO SECONDARY SCHOOL',
 | 
			
		||||
      ]);
 | 
			
		||||
 | 
			
		||||
      await driver.sendKeys(Key.DOWN, Key.ENTER, Key.ENTER);
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      assert.equal(await cell.getText(), 'ST BRENDAN SCHOOL');
 | 
			
		||||
      await gu.undo();
 | 
			
		||||
      assert.equal(await cell.getText(), '');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should highlight matching parts of items', async function() {
 | 
			
		||||
      await driver.sendKeys(Key.HOME);
 | 
			
		||||
 | 
			
		||||
      let cell = await gu.getCell({section: 'References', col: 'Colors', rowNum: 2}).doClick();
 | 
			
		||||
      assert.equal(await cell.getText(), 'Red');
 | 
			
		||||
      await driver.sendKeys(Key.ENTER, 'Red');
 | 
			
		||||
      await driver.findWait('.test-ref-editor-item', 1000);
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await driver.findContent('.test-ref-editor-item', /Dark Red/).findAll('span', e => e.getText()),
 | 
			
		||||
        ['Red']);
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await driver.findContent('.test-ref-editor-item', /Rebecca Purple/).findAll('span', e => e.getText()),
 | 
			
		||||
        ['Re']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      cell = await gu.getCell({section: 'References', col: 'Schools', rowNum: 1}).doClick();
 | 
			
		||||
      await driver.sendKeys('br tech');
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await driver.findContentWait('.test-ref-editor-item', /BROOKLYN TECH/, 1000).findAll('span', e => e.getText()),
 | 
			
		||||
        ['BR', 'TECH']);
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await driver.findContent('.test-ref-editor-item', /BUFFALO.*TECHNOLOGY/).findAll('span', e => e.getText()),
 | 
			
		||||
        ['B', 'TECH']);
 | 
			
		||||
      assert.deepEqual(
 | 
			
		||||
        await driver.findContent('.test-ref-editor-item', /ENERGY TECH/).findAll('span', e => e.getText()),
 | 
			
		||||
        ['TECH']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should reflect changes to the target column', async function() {
 | 
			
		||||
      await driver.sendKeys(Key.HOME);
 | 
			
		||||
 | 
			
		||||
      const cell = await gu.getCell({section: 'References', col: 'Colors', rowNum: 4}).doClick();
 | 
			
		||||
      assert.equal(await cell.getText(), '');
 | 
			
		||||
      await driver.sendKeys(Key.ENTER);
 | 
			
		||||
      assert.deepEqual(await getACOptions(2), ['Alice Blue', 'Añil']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      // Change a color
 | 
			
		||||
      await gu.getCell({section: 'Colors', col: 'Color Name', rowNum: 1}).doClick();
 | 
			
		||||
      await driver.sendKeys('HAZELNUT', Key.ENTER);
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // See that the old value is gone from the autocomplete, and the new one is present.
 | 
			
		||||
      await cell.click();
 | 
			
		||||
      await driver.sendKeys(Key.ENTER);
 | 
			
		||||
      assert.deepEqual(await getACOptions(2), ['Añil', 'Aqua']);
 | 
			
		||||
      await driver.sendKeys('H');
 | 
			
		||||
      assert.deepEqual(await getACOptions(2), ['HAZELNUT', 'Honeydew']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      // Delete a row.
 | 
			
		||||
      await gu.getCell({section: 'Colors', col: 'Color Name', rowNum: 1}).doClick();
 | 
			
		||||
      await driver.find('body').sendKeys(Key.chord(await gu.modKey(), '-'));
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // See that the value is gone from the autocomplete.
 | 
			
		||||
      await cell.click();
 | 
			
		||||
      await driver.sendKeys('H');
 | 
			
		||||
      assert.deepEqual(await getACOptions(2), ['Honeydew', 'Hot Pink']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      // Add a row.
 | 
			
		||||
      await gu.getCell({section: 'Colors', col: 'Color Name', rowNum: 1}).doClick();
 | 
			
		||||
      await driver.find('body').sendKeys(Key.chord(await gu.modKey(), '='));
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
      await driver.sendKeys('HELIOTROPE', Key.ENTER);
 | 
			
		||||
      await gu.waitForServer();
 | 
			
		||||
 | 
			
		||||
      // See that the new value is visible in the autocomplete.
 | 
			
		||||
      await cell.click();
 | 
			
		||||
      await driver.sendKeys('H');
 | 
			
		||||
      assert.deepEqual(await getACOptions(2), ['HELIOTROPE', 'Honeydew']);
 | 
			
		||||
      await driver.sendKeys(Key.BACK_SPACE);
 | 
			
		||||
      assert.deepEqual(await getACOptions(2), ['Añil', 'Aqua']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
 | 
			
		||||
      // Undo all the changes.
 | 
			
		||||
      await gu.undo(4);
 | 
			
		||||
 | 
			
		||||
      await cell.click();
 | 
			
		||||
      await driver.sendKeys('H');
 | 
			
		||||
      assert.deepEqual(await getACOptions(2), ['Honeydew', 'Hot Pink']);
 | 
			
		||||
      await driver.sendKeys(Key.BACK_SPACE);
 | 
			
		||||
      assert.deepEqual(await getACOptions(2), ['Alice Blue', 'Añil']);
 | 
			
		||||
      await driver.sendKeys(Key.ESCAPE);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user