mirror of
				https://github.com/gristlabs/grist-core.git
				synced 2025-06-13 20:53:59 +00:00 
			
		
		
		
	(core) Add tests and tooltips to new Add Column menu
Summary: Adds tooltips to the menu and tests for recently-added functionality. Test Plan: Browser tests. Reviewers: JakubSerafin Reviewed By: JakubSerafin Subscribers: JakubSerafin Differential Revision: https://phab.getgrist.com/D4087
This commit is contained in:
		
							parent
							
								
									69d5ee53a8
								
							
						
					
					
						commit
						de33c5a3c6
					
				@ -3,6 +3,8 @@ import GridView from 'app/client/components/GridView';
 | 
			
		||||
import {makeT} from 'app/client/lib/localization';
 | 
			
		||||
import {ViewSectionRec} from 'app/client/models/DocModel';
 | 
			
		||||
import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec';
 | 
			
		||||
import {GristTooltips} from 'app/client/ui/GristTooltips';
 | 
			
		||||
import {withInfoTooltip} from 'app/client/ui/tooltips';
 | 
			
		||||
import {testId, theme, vars} from 'app/client/ui2018/cssVars';
 | 
			
		||||
import {icon} from 'app/client/ui2018/icons';
 | 
			
		||||
import {
 | 
			
		||||
@ -265,7 +267,11 @@ function buildUUIDMenuItem(gridView: GridView, index?: number) {
 | 
			
		||||
        await gridView.gristDoc.convertToTrigger(colRef, 'UUID()');
 | 
			
		||||
      }, {nestInActiveBundle: true});
 | 
			
		||||
    },
 | 
			
		||||
    t('UUID'),
 | 
			
		||||
    withInfoTooltip(
 | 
			
		||||
      t('UUID'),
 | 
			
		||||
      GristTooltips.uuid(),
 | 
			
		||||
      {variant: 'hover'}
 | 
			
		||||
    ),
 | 
			
		||||
    testId('new-columns-menu-shortcuts-uuid'),
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
@ -522,8 +528,15 @@ function buildLookupSection(gridView: GridView, index?: number){
 | 
			
		||||
    : [lookupMenu, reverseLookupMenu];
 | 
			
		||||
 | 
			
		||||
  return [
 | 
			
		||||
      menuDivider(),
 | 
			
		||||
      menuSubHeader(t("Lookups"), testId('new-columns-menu-lookups')),
 | 
			
		||||
    menuDivider(),
 | 
			
		||||
    menuSubHeader(
 | 
			
		||||
      withInfoTooltip(
 | 
			
		||||
        t('Lookups'),
 | 
			
		||||
        GristTooltips.lookups(),
 | 
			
		||||
        {variant: 'hover'}
 | 
			
		||||
      ),
 | 
			
		||||
      testId('new-columns-menu-lookups'),
 | 
			
		||||
    ),
 | 
			
		||||
    ...menuContent
 | 
			
		||||
    ];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -35,7 +35,9 @@ export type Tooltip =
 | 
			
		||||
  | 'workOnACopy'
 | 
			
		||||
  | 'openAccessRules'
 | 
			
		||||
  | 'addRowConditionalStyle'
 | 
			
		||||
  | 'addColumnConditionalStyle';
 | 
			
		||||
  | 'addColumnConditionalStyle'
 | 
			
		||||
  | 'uuid'
 | 
			
		||||
  | 'lookups';
 | 
			
		||||
 | 
			
		||||
export type TooltipContentFunc = (...domArgs: DomElementArg[]) => DomContents;
 | 
			
		||||
 | 
			
		||||
@ -98,6 +100,21 @@ see or edit which parts of your document.')
 | 
			
		||||
    ),
 | 
			
		||||
    ...args,
 | 
			
		||||
  ),
 | 
			
		||||
  uuid: (...args: DomElementArg[]) => cssTooltipContent(
 | 
			
		||||
    dom('div', t('A UUID is a randomly-generated string that is useful for unique identifiers and link keys.')),
 | 
			
		||||
    dom('div',
 | 
			
		||||
      cssLink({href: commonUrls.helpLinkKeys, target: '_blank'}, t('Learn more.')),
 | 
			
		||||
    ),
 | 
			
		||||
    ...args,
 | 
			
		||||
  ),
 | 
			
		||||
  lookups: (...args: DomElementArg[]) => cssTooltipContent(
 | 
			
		||||
    dom('div', t('Lookups return data from related tables.')),
 | 
			
		||||
    dom('div', t('Use reference columns to relate data in different tables.')),
 | 
			
		||||
    dom('div',
 | 
			
		||||
      cssLink({href: commonUrls.helpColRefs, target: '_blank'}, t('Learn more.')),
 | 
			
		||||
    ),
 | 
			
		||||
    ...args,
 | 
			
		||||
  ),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export interface BehavioralPromptContent {
 | 
			
		||||
 | 
			
		||||
@ -386,7 +386,7 @@ export class PageWidgetSelect extends Disposable {
 | 
			
		||||
                          testId('selectby'))
 | 
			
		||||
              ),
 | 
			
		||||
              GristTooltips.selectBy(),
 | 
			
		||||
              {tooltipMenuOptions: {attach: null}, domArgs: [
 | 
			
		||||
              {popupOptions: {attach: null}, domArgs: [
 | 
			
		||||
                this._behavioralPromptsManager.attachTip('pageWidgetPickerSelectBy', {
 | 
			
		||||
                  popupOptions: {
 | 
			
		||||
                    attach: null,
 | 
			
		||||
 | 
			
		||||
@ -256,7 +256,7 @@ function menuWorkOnCopy(pageModel: DocPageModel) {
 | 
			
		||||
      withInfoTooltip(
 | 
			
		||||
        t("Edit without affecting the original"),
 | 
			
		||||
        GristTooltips.workOnACopy(),
 | 
			
		||||
        {tooltipMenuOptions: {attach: null}}
 | 
			
		||||
        {popupOptions: {attach: null}}
 | 
			
		||||
      )
 | 
			
		||||
    ),
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,7 @@ import {makeLinks} from 'app/client/ui2018/links';
 | 
			
		||||
import {menuCssClass} from 'app/client/ui2018/menus';
 | 
			
		||||
import {dom, DomContents, DomElementArg, DomElementMethod, styled} from 'grainjs';
 | 
			
		||||
import Popper from 'popper.js';
 | 
			
		||||
import {cssMenu, defaultMenuOptions, IMenuOptions, setPopupToCreateDom} from 'popweasel';
 | 
			
		||||
import {cssMenu, cssMenuItem, defaultMenuOptions, IPopupOptions, setPopupToCreateDom} from 'popweasel';
 | 
			
		||||
import merge = require('lodash/merge');
 | 
			
		||||
 | 
			
		||||
export interface ITipOptions {
 | 
			
		||||
@ -307,10 +307,41 @@ export function tooltipCloseButton(ctl: ITooltipControl): HTMLElement {
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface InfoTooltipOptions {
 | 
			
		||||
  /** Defaults to `click`. */
 | 
			
		||||
  variant?: InfoTooltipVariant;
 | 
			
		||||
  /** Only applicable to the `click` variant. */
 | 
			
		||||
  popupOptions?: IPopupOptions;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type InfoTooltipVariant = 'click' | 'hover';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Renders an info icon that shows a tooltip with the specified `content` on click.
 | 
			
		||||
 * Renders an info icon that shows a tooltip with the specified `content`.
 | 
			
		||||
 */
 | 
			
		||||
export function infoTooltip(content: DomContents, menuOptions?: IMenuOptions, ...domArgs: DomElementArg[]) {
 | 
			
		||||
export function infoTooltip(
 | 
			
		||||
  content: DomContents,
 | 
			
		||||
  options: InfoTooltipOptions = {},
 | 
			
		||||
  ...domArgs: DomElementArg[]
 | 
			
		||||
) {
 | 
			
		||||
  const {variant = 'click'} = options;
 | 
			
		||||
  switch (variant) {
 | 
			
		||||
    case 'click': {
 | 
			
		||||
      const {popupOptions} = options;
 | 
			
		||||
      return buildClickableInfoTooltip(content, popupOptions, domArgs);
 | 
			
		||||
    }
 | 
			
		||||
    case 'hover': {
 | 
			
		||||
      return buildHoverableInfoTooltip(content, domArgs);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function buildClickableInfoTooltip(
 | 
			
		||||
  content: DomContents,
 | 
			
		||||
  popupOptions?: IPopupOptions,
 | 
			
		||||
  ...domArgs: DomElementArg[]
 | 
			
		||||
) {
 | 
			
		||||
  return cssInfoTooltipButton('?',
 | 
			
		||||
    (elem) => {
 | 
			
		||||
      setPopupToCreateDom(
 | 
			
		||||
@ -336,7 +367,7 @@ export function infoTooltip(content: DomContents, menuOptions?: IMenuOptions, ..
 | 
			
		||||
            testId('info-tooltip-popup'),
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
        {...defaultMenuOptions, ...{placement: 'bottom-end'}, ...menuOptions},
 | 
			
		||||
        {...defaultMenuOptions, ...{placement: 'bottom-end'}, ...popupOptions},
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
    testId('info-tooltip'),
 | 
			
		||||
@ -344,22 +375,41 @@ export function infoTooltip(content: DomContents, menuOptions?: IMenuOptions, ..
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function buildHoverableInfoTooltip(content: DomContents, ...domArgs: DomElementArg[]) {
 | 
			
		||||
  return cssInfoTooltipIcon('?',
 | 
			
		||||
    hoverTooltip(() => cssInfoTooltipTransientPopup(
 | 
			
		||||
      content,
 | 
			
		||||
      cssTooltipCorner(testId('tooltip-origin')),
 | 
			
		||||
      {tabIndex: '-1'},
 | 
			
		||||
      testId('info-tooltip-popup'),
 | 
			
		||||
    ), {closeOnClick: false}),
 | 
			
		||||
    testId('info-tooltip'),
 | 
			
		||||
    ...domArgs,
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface WithInfoTooltipOptions {
 | 
			
		||||
  /** Defaults to `click`. */
 | 
			
		||||
  variant?: InfoTooltipVariant;
 | 
			
		||||
  domArgs?: DomElementArg[];
 | 
			
		||||
  tooltipButtonDomArgs?: DomElementArg[];
 | 
			
		||||
  tooltipMenuOptions?: IMenuOptions;
 | 
			
		||||
  iconDomArgs?: DomElementArg[];
 | 
			
		||||
  /** Only applicable to the `click` variant. */
 | 
			
		||||
  popupOptions?: IPopupOptions;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Wraps `domContent` with a info tooltip button that displays the provided
 | 
			
		||||
 * `tooltipContent` on click, and returns the wrapped element.
 | 
			
		||||
 * Wraps `domContent` with a info tooltip icon that displays the provided
 | 
			
		||||
 * `tooltipContent` and returns the wrapped element.
 | 
			
		||||
 *
 | 
			
		||||
 * The tooltip button is displayed to the right of `domContents`, and displays
 | 
			
		||||
 * a popup on click. The popup can be dismissed by clicking away from it, clicking
 | 
			
		||||
 * the close button in the top-right corner, or pressing Enter or Escape.
 | 
			
		||||
 * a popup on click by default. The popup can be dismissed by clicking away from
 | 
			
		||||
 * it; clicking the close button in the top-right corner; or pressing Enter or Escape.
 | 
			
		||||
 *
 | 
			
		||||
 * You may optionally specify `options.variant`, which controls whether the tooltip
 | 
			
		||||
 * is shown on hover or on click.
 | 
			
		||||
 *
 | 
			
		||||
 * Arguments can be passed to both the top-level wrapped DOM element and the
 | 
			
		||||
 * tooltip button element with `options.domArgs` and `options.tooltipButtonDomArgs`
 | 
			
		||||
 * tooltip icon element with `options.domArgs` and `options.tooltipIconDomArgs`
 | 
			
		||||
 * respectively.
 | 
			
		||||
 *
 | 
			
		||||
 * Usage:
 | 
			
		||||
@ -374,10 +424,10 @@ export function withInfoTooltip(
 | 
			
		||||
  tooltipContent: DomContents,
 | 
			
		||||
  options: WithInfoTooltipOptions = {},
 | 
			
		||||
) {
 | 
			
		||||
  const {domArgs, tooltipButtonDomArgs, tooltipMenuOptions} = options;
 | 
			
		||||
  const {variant = 'click', domArgs, iconDomArgs, popupOptions} = options;
 | 
			
		||||
  return cssDomWithTooltip(
 | 
			
		||||
    domContents,
 | 
			
		||||
    infoTooltip(tooltipContent, tooltipMenuOptions, tooltipButtonDomArgs),
 | 
			
		||||
    infoTooltip(tooltipContent, {variant, popupOptions}, iconDomArgs),
 | 
			
		||||
    ...(domArgs ?? [])
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
@ -395,7 +445,7 @@ export function descriptionInfoTooltip(
 | 
			
		||||
    key: 'columnDescription',
 | 
			
		||||
    openOnClick: true,
 | 
			
		||||
  };
 | 
			
		||||
  const builder = () => cssDescriptionInfoTooltip(
 | 
			
		||||
  const builder = () => cssInfoTooltipTransientPopup(
 | 
			
		||||
    body,
 | 
			
		||||
    // Used id test to find the origin of the tooltip regardless webdriver implementation (some of them start)
 | 
			
		||||
    cssTooltipCorner(testId('tooltip-origin')),
 | 
			
		||||
@ -422,7 +472,7 @@ const cssTooltipCorner = styled('div', `
 | 
			
		||||
  visibility: hidden;
 | 
			
		||||
`);
 | 
			
		||||
 | 
			
		||||
const cssDescriptionInfoTooltip = styled('div', `
 | 
			
		||||
const cssInfoTooltipTransientPopup = styled('div', `
 | 
			
		||||
  position: relative;
 | 
			
		||||
  white-space: pre-wrap;
 | 
			
		||||
  text-align: left;
 | 
			
		||||
@ -489,7 +539,7 @@ const cssTooltipCloseButton = styled('div', `
 | 
			
		||||
  }
 | 
			
		||||
`);
 | 
			
		||||
 | 
			
		||||
const cssInfoTooltipButton = styled('div', `
 | 
			
		||||
const cssInfoTooltipIcon = styled('div', `
 | 
			
		||||
  flex-shrink: 0;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
@ -499,9 +549,17 @@ const cssInfoTooltipButton = styled('div', `
 | 
			
		||||
  border: 1px solid ${theme.controlSecondaryFg};
 | 
			
		||||
  color: ${theme.controlSecondaryFg};
 | 
			
		||||
  border-radius: 50%;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  user-select: none;
 | 
			
		||||
 | 
			
		||||
  .${cssMenuItem.className}-sel & {
 | 
			
		||||
    color: ${theme.menuItemSelectedFg};
 | 
			
		||||
    border-color: ${theme.menuItemSelectedFg};
 | 
			
		||||
  }
 | 
			
		||||
`);
 | 
			
		||||
 | 
			
		||||
const cssInfoTooltipButton = styled(cssInfoTooltipIcon, `
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
 | 
			
		||||
  &:hover {
 | 
			
		||||
    border: 1px solid ${theme.controlSecondaryHoverFg};
 | 
			
		||||
    color: ${theme.controlSecondaryHoverFg};
 | 
			
		||||
 | 
			
		||||
@ -80,6 +80,7 @@ export function searchableMenu(
 | 
			
		||||
          dom.autoDispose(searchValue),
 | 
			
		||||
          dom.on('input', (_ev, elem) => { setSearchValue(elem.value); }),
 | 
			
		||||
          {placeholder: searchInputPlaceholder},
 | 
			
		||||
          testId('searchable-menu-input'),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    ),
 | 
			
		||||
@ -97,6 +98,7 @@ export function searchableMenu(
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    }),
 | 
			
		||||
    testId('searchable-menu'),
 | 
			
		||||
  ];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -80,6 +80,7 @@ export const commonUrls = {
 | 
			
		||||
  helpCustomWidgets: "https://support.getgrist.com/widget-custom",
 | 
			
		||||
  helpTelemetryLimited: "https://support.getgrist.com/telemetry-limited",
 | 
			
		||||
  helpCalendarWidget: "https://support.getgrist.com/widget-calendar",
 | 
			
		||||
  helpLinkKeys: "https://support.getgrist.com/examples/2021-04-link-keys",
 | 
			
		||||
  plans: "https://www.getgrist.com/pricing",
 | 
			
		||||
  sproutsProgram: "https://www.getgrist.com/sprouts-program",
 | 
			
		||||
  contact: "https://www.getgrist.com/contact",
 | 
			
		||||
 | 
			
		||||
@ -68,7 +68,7 @@ describe('GridViewNewColumnMenu', function () {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('column creation', function () {
 | 
			
		||||
      it('should show rename menu  after new column click', async function () {
 | 
			
		||||
      it('should show rename menu after new column click', async function () {
 | 
			
		||||
        const menu = await openAddColumnIcon();
 | 
			
		||||
        await menu.findWait('.test-new-columns-menu-add-new', 100).click();
 | 
			
		||||
        await driver.findWait('.test-column-title-popup', 100, 'rename menu is not present');
 | 
			
		||||
@ -86,6 +86,39 @@ describe('GridViewNewColumnMenu', function () {
 | 
			
		||||
        assert.lengthOf(columns, 4, 'wrong number of columns');
 | 
			
		||||
        await gu.undo();
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      it('should support inserting before selected column', async function () {
 | 
			
		||||
        await gu.openColumnMenu('A', 'Insert column to the left');
 | 
			
		||||
        await driver.findWait(".test-new-columns-menu", 100);
 | 
			
		||||
        await gu.sendKeys(Key.ENTER);
 | 
			
		||||
        await gu.waitForServer();
 | 
			
		||||
        await driver.findWait('.test-column-title-close', 100).click();
 | 
			
		||||
        const columns = await gu.getColumnNames();
 | 
			
		||||
        assert.deepEqual(columns, ['D', 'A', 'B', 'C']);
 | 
			
		||||
        await gu.undo();
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      it('should support inserting after selected column', async function () {
 | 
			
		||||
        await gu.openColumnMenu('A', 'Insert column to the right');
 | 
			
		||||
        await driver.findWait(".test-new-columns-menu", 100);
 | 
			
		||||
        await gu.sendKeys(Key.ENTER);
 | 
			
		||||
        await gu.waitForServer();
 | 
			
		||||
        await driver.findWait('.test-column-title-close', 100).click();
 | 
			
		||||
        const columns = await gu.getColumnNames();
 | 
			
		||||
        assert.deepEqual(columns, ['A', 'D', 'B', 'C']);
 | 
			
		||||
        await gu.undo();
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      it('should support inserting after the last visible column', async function () {
 | 
			
		||||
        await gu.openColumnMenu('C', 'Insert column to the right');
 | 
			
		||||
        await driver.findWait(".test-new-columns-menu", 100);
 | 
			
		||||
        await gu.sendKeys(Key.ENTER);
 | 
			
		||||
        await gu.waitForServer();
 | 
			
		||||
        await driver.findWait('.test-column-title-close', 100).click();
 | 
			
		||||
        const columns = await gu.getColumnNames();
 | 
			
		||||
        assert.deepEqual(columns, ['A', 'B', 'C', 'D']);
 | 
			
		||||
        await gu.undo();
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('hidden columns', function () {
 | 
			
		||||
@ -103,13 +136,13 @@ describe('GridViewNewColumnMenu', function () {
 | 
			
		||||
          await gu.addColumn('Add3');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('1 to 5 hidden columns, secion should be inline', async function () {
 | 
			
		||||
        it('1 to 5 hidden columns, section should be inline', async function () {
 | 
			
		||||
          const checkSection = async (...columns: string[]) => {
 | 
			
		||||
            const menu = await openAddColumnIcon();
 | 
			
		||||
            await menu.findWait(".test-new-columns-menu-hidden-columns", 100,
 | 
			
		||||
              'hidden section is not present');
 | 
			
		||||
            for (const column of columns) {
 | 
			
		||||
              const isColumnPresent = await menu.find(`.test-new-columns-menu-hidden-columns-${column}`).isPresent();
 | 
			
		||||
              const isColumnPresent = await menu.findContent('li', column).isPresent();
 | 
			
		||||
              assert.isTrue(isColumnPresent, `column ${column} is not present`);
 | 
			
		||||
            }
 | 
			
		||||
            await closeAddColumnMenu();
 | 
			
		||||
@ -123,7 +156,7 @@ describe('GridViewNewColumnMenu', function () {
 | 
			
		||||
          await gu.moveToHidden('Add1');
 | 
			
		||||
          await gu.moveToHidden('Add2');
 | 
			
		||||
          await checkSection('A', 'B', 'C', 'Add1', 'Add2');
 | 
			
		||||
          await gu.undo(5);
 | 
			
		||||
          await gu.undo(11);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('inline button should show column at the end of the table', async function () {
 | 
			
		||||
@ -156,11 +189,7 @@ describe('GridViewNewColumnMenu', function () {
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('shortucts', function () {
 | 
			
		||||
      describe('Timestamp', function () {
 | 
			
		||||
        it('created at - should create new column with date triggered on create');
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    describe('shortcuts', function () {
 | 
			
		||||
      describe('Timestamp', function () {
 | 
			
		||||
        it('created at - should create new column with date triggered on create', function () {
 | 
			
		||||
 | 
			
		||||
@ -178,6 +207,84 @@ describe('GridViewNewColumnMenu', function () {
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      describe('Detect Duplicates in...', function () {
 | 
			
		||||
        it('should show columns in a searchable sub-menu', async function () {
 | 
			
		||||
          const menu = await openAddColumnIcon();
 | 
			
		||||
          await menu.findWait('.test-new-columns-menu-shortcuts-duplicates', 100).mouseMove();
 | 
			
		||||
          await gu.waitToPass(async () => {
 | 
			
		||||
            assert.deepEqual(
 | 
			
		||||
              await driver.findAll('.test-searchable-menu li', (el) => el.getText()),
 | 
			
		||||
              ['A', 'B', 'C']
 | 
			
		||||
            );
 | 
			
		||||
          }, 500);
 | 
			
		||||
          await driver.find('.test-searchable-menu-input').click();
 | 
			
		||||
          await gu.sendKeys('A');
 | 
			
		||||
          await gu.waitToPass(async () => {
 | 
			
		||||
            assert.deepEqual(
 | 
			
		||||
              await driver.findAll('.test-searchable-menu li', (el) => el.getText()),
 | 
			
		||||
              ['A']
 | 
			
		||||
            );
 | 
			
		||||
          }, 250);
 | 
			
		||||
 | 
			
		||||
          await gu.sendKeys('BC');
 | 
			
		||||
          await gu.waitToPass(async () => {
 | 
			
		||||
            assert.deepEqual(
 | 
			
		||||
              await driver.findAll('.test-searchable-menu li', (el) => el.getText()),
 | 
			
		||||
              []
 | 
			
		||||
            );
 | 
			
		||||
          }, 250);
 | 
			
		||||
 | 
			
		||||
          await gu.clearInput();
 | 
			
		||||
          await gu.waitToPass(async () => {
 | 
			
		||||
            assert.deepEqual(
 | 
			
		||||
              await driver.findAll('.test-searchable-menu li', (el) => el.getText()),
 | 
			
		||||
              ['A', 'B', 'C']
 | 
			
		||||
            );
 | 
			
		||||
          }, 250);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should create new column that checks for duplicates in the specified column', async function () {
 | 
			
		||||
          const menu = await openAddColumnIcon();
 | 
			
		||||
          await menu.findWait('.test-new-columns-menu-shortcuts-duplicates', 100).mouseMove();
 | 
			
		||||
          await driver.findContentWait('.test-searchable-menu li', 'A', 500).click();
 | 
			
		||||
          await gu.waitForServer();
 | 
			
		||||
          await gu.sendKeys(Key.ENTER);
 | 
			
		||||
 | 
			
		||||
          // Just checking the formula looks plausible - correctness is best left to a python test.
 | 
			
		||||
          assert.equal(
 | 
			
		||||
            await driver.find('.test-formula-editor').getText(),
 | 
			
		||||
            'True if len(Table1.lookupRecords(A=$A)) > 1 else False'
 | 
			
		||||
          );
 | 
			
		||||
          await gu.sendKeys(Key.ESCAPE);
 | 
			
		||||
          const columns = await gu.getColumnNames();
 | 
			
		||||
          assert.deepEqual(columns, ['A', 'B', 'C', 'Duplicate in A']);
 | 
			
		||||
          await gu.undo();
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      describe('UUID', function () {
 | 
			
		||||
        it('should create new column that generates a UUID on new record', async function () {
 | 
			
		||||
          await gu.getCell(2, 1).click();
 | 
			
		||||
          await gu.sendKeys('A', Key.ENTER);
 | 
			
		||||
          await gu.waitForServer();
 | 
			
		||||
          const menu = await openAddColumnIcon();
 | 
			
		||||
          await menu.findWait('.test-new-columns-menu-shortcuts-uuid', 100).click();
 | 
			
		||||
          await gu.waitForServer();
 | 
			
		||||
          const cells1 = await gu.getVisibleGridCells({col: 'UUID', rowNums: [1, 2]});
 | 
			
		||||
          assert.match(cells1[0], /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/);
 | 
			
		||||
          assert.equal(cells1[1], '');
 | 
			
		||||
          await gu.getCell(2, 2).click();
 | 
			
		||||
          await gu.sendKeys('B', Key.ENTER);
 | 
			
		||||
          await gu.waitForServer();
 | 
			
		||||
          const cells2 = await gu.getVisibleGridCells({col: 'UUID', rowNums: [1, 2, 3]});
 | 
			
		||||
          assert.match(cells2[0], /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/);
 | 
			
		||||
          assert.match(cells2[1], /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/);
 | 
			
		||||
          assert.equal(cells2[2], '');
 | 
			
		||||
          assert.equal(cells1[0], cells2[0]);
 | 
			
		||||
          await gu.undo(3);
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user