mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Forms post-release fixes and improvements
Summary: Fixes misc. bugs with forms, updates Grist URLs on static form pages to link to the new forms marketing page, and adds a forms announcement popup that's shown next to the Add New button within a document. Test Plan: Browser tests. Reviewers: jarek Reviewed By: jarek Differential Revision: https://phab.getgrist.com/D4185
This commit is contained in:
268
test/nbrowser/BehavioralPrompts.ts
Normal file
268
test/nbrowser/BehavioralPrompts.ts
Normal file
@@ -0,0 +1,268 @@
|
||||
import {assert, driver, Key} from 'mocha-webdriver';
|
||||
import * as gu from 'test/nbrowser/gristUtils';
|
||||
import {setupTestSuite} from 'test/nbrowser/testUtils';
|
||||
|
||||
describe('BehavioralPrompts', function() {
|
||||
this.timeout(20000);
|
||||
const cleanup = setupTestSuite();
|
||||
|
||||
let session: gu.Session;
|
||||
let docId: string;
|
||||
|
||||
before(async () => {
|
||||
session = await gu.session().user('user1').login({showTips: true});
|
||||
await gu.dismissCoachingCall();
|
||||
docId = await session.tempNewDoc(cleanup, 'BehavioralPrompts');
|
||||
});
|
||||
|
||||
afterEach(() => gu.checkForErrors());
|
||||
|
||||
describe('when helpCenter is hidden', function() {
|
||||
gu.withEnvironmentSnapshot({'GRIST_HIDE_UI_ELEMENTS': 'helpCenter'});
|
||||
|
||||
before(async () => {
|
||||
const sessionNoHelpCenter = await gu.session().user('user3').login({
|
||||
isFirstLogin: false,
|
||||
freshAccount: true,
|
||||
showTips: true,
|
||||
});
|
||||
await gu.dismissCoachingCall();
|
||||
await sessionNoHelpCenter.tempNewDoc(cleanup, 'BehavioralPromptsNoHelpCenter');
|
||||
});
|
||||
|
||||
it('should not be shown', async function() {
|
||||
await assertPromptTitle(null);
|
||||
await gu.toggleSidePanel('right', 'open');
|
||||
await driver.find('.test-right-tab-field').click();
|
||||
await driver.find('.test-fbuilder-type-select').click();
|
||||
await assertPromptTitle(null);
|
||||
});
|
||||
});
|
||||
|
||||
it('should show an announcement for forms', async function() {
|
||||
await assertPromptTitle('Forms are here!');
|
||||
await gu.dismissBehavioralPrompts();
|
||||
});
|
||||
|
||||
describe('when anonymous', function() {
|
||||
before(async () => {
|
||||
const anonymousSession = await gu.session().anon.login({
|
||||
showTips: true,
|
||||
});
|
||||
await anonymousSession.loadDocMenu('/');
|
||||
await driver.find('.test-intro-create-doc').click();
|
||||
await gu.waitForDocToLoad();
|
||||
});
|
||||
|
||||
it('should not shown an announcement for forms', async function() {
|
||||
await assertPromptTitle(null);
|
||||
});
|
||||
});
|
||||
|
||||
it('should be shown when the column type select menu is opened', async function() {
|
||||
await gu.toggleSidePanel('right', 'open');
|
||||
await driver.find('.test-right-tab-field').click();
|
||||
await driver.find('.test-fbuilder-type-select').click();
|
||||
await assertPromptTitle('Reference Columns');
|
||||
});
|
||||
|
||||
it('should be temporarily dismissed on click-away', async function() {
|
||||
await gu.getCell({col: 'A', rowNum: 1}).click();
|
||||
await assertPromptTitle(null);
|
||||
});
|
||||
|
||||
it('should be shown again the next time the menu is opened', async function() {
|
||||
await driver.find('.test-fbuilder-type-select').click();
|
||||
await assertPromptTitle('Reference Columns');
|
||||
});
|
||||
|
||||
it('should be permanently dismissed when "Got it" is clicked', async function() {
|
||||
await gu.dismissBehavioralPrompts();
|
||||
await assertPromptTitle(null);
|
||||
|
||||
// Refresh the page and make sure the prompt isn't shown again.
|
||||
await session.loadDoc(`/doc/${docId}`);
|
||||
await driver.find('.test-fbuilder-type-select').click();
|
||||
await assertPromptTitle(null);
|
||||
await gu.sendKeys(Key.ESCAPE);
|
||||
});
|
||||
|
||||
it('should be shown after selecting a reference column type', async function() {
|
||||
await gu.setType(/Reference$/);
|
||||
await assertPromptTitle('Reference Columns');
|
||||
await gu.undo();
|
||||
});
|
||||
|
||||
it('should be shown after selecting a reference list column type', async function() {
|
||||
await gu.setType(/Reference List$/);
|
||||
await assertPromptTitle('Reference Columns');
|
||||
});
|
||||
|
||||
it('should be shown when opening the Raw Data page', async function() {
|
||||
await driver.find('.test-tools-raw').click();
|
||||
await assertPromptTitle('Raw Data page');
|
||||
});
|
||||
|
||||
it('should be shown when opening the Access Rules page', async function() {
|
||||
await driver.find('.test-tools-access-rules').click();
|
||||
await assertPromptTitle('Access Rules');
|
||||
});
|
||||
|
||||
it('should be shown when opening the filter menu', async function() {
|
||||
await gu.openPage('Table1');
|
||||
await gu.openColumnMenu('A', 'Filter');
|
||||
await assertPromptTitle('Pinning Filters');
|
||||
await gu.dismissBehavioralPrompts();
|
||||
});
|
||||
|
||||
it('should be shown when adding a second pinned filter', async function() {
|
||||
await driver.find('.test-filter-menu-apply-btn').click();
|
||||
await assertPromptTitle(null);
|
||||
await gu.openColumnMenu('B', 'Filter');
|
||||
await driver.find('.test-filter-menu-apply-btn').click();
|
||||
await assertPromptTitle('Nested Filtering');
|
||||
});
|
||||
|
||||
it('should be shown when opening the page widget picker', async function() {
|
||||
await gu.openAddWidgetToPage();
|
||||
await assertPromptTitle('Selecting Data');
|
||||
await gu.dismissBehavioralPrompts();
|
||||
});
|
||||
|
||||
it('should be shown when select by is an available option', async function() {
|
||||
await driver.findContent('.test-wselect-table', /Table1/).click();
|
||||
await assertPromptTitle('Linking Widgets');
|
||||
await gu.dismissBehavioralPrompts();
|
||||
});
|
||||
|
||||
it('should be shown when adding a card widget', async function() {
|
||||
await gu.selectWidget('Card', /Table1/);
|
||||
await assertPromptTitle('Editing Card Layout');
|
||||
});
|
||||
|
||||
it('should not be shown when adding a non-card widget', async function() {
|
||||
await gu.addNewPage('Table', /Table1/);
|
||||
await assertPromptTitle(null);
|
||||
});
|
||||
|
||||
it('should be shown when adding a card list widget', async function() {
|
||||
await gu.addNewPage('Card List', /Table1/);
|
||||
await assertPromptTitle('Editing Card Layout');
|
||||
});
|
||||
|
||||
it('should be shown after adding custom view as a new page', async function() {
|
||||
await gu.addNewPage('Custom', 'Table1');
|
||||
await assertPromptTitle('Custom Widgets');
|
||||
await gu.undo();
|
||||
});
|
||||
|
||||
it('should be shown after adding custom section', async function() {
|
||||
await gu.addNewSection('Custom', 'Table1');
|
||||
await assertPromptTitle('Custom Widgets');
|
||||
await gu.undo();
|
||||
});
|
||||
|
||||
describe('for the Add New button', function() {
|
||||
it('should not be shown if site is empty', async function() {
|
||||
session = await gu.session().user('user4').login({showTips: true});
|
||||
await gu.dismissCoachingCall();
|
||||
await driver.navigate().refresh();
|
||||
await gu.loadDocMenu('/');
|
||||
await assertPromptTitle(null);
|
||||
});
|
||||
|
||||
it('should be shown if site has documents', async function() {
|
||||
await session.tempNewDoc(cleanup, 'BehavioralPromptsAddNew');
|
||||
await session.loadDocMenu('/');
|
||||
await assertPromptTitle('Add New');
|
||||
});
|
||||
|
||||
it('should not be shown on the Trash page', async function() {
|
||||
// Load /p/trash and check that tip isn't initially shown.
|
||||
await session.loadDocMenu('/p/trash');
|
||||
await assertPromptTitle(null);
|
||||
});
|
||||
|
||||
it('should only be shown once each visit to the doc menu', async function() {
|
||||
// Navigate to another page without reloading; the tip should now be shown.
|
||||
await driver.find('.test-dm-all-docs').click();
|
||||
await gu.waitForDocMenuToLoad();
|
||||
await assertPromptTitle('Add New');
|
||||
|
||||
// Navigate to another page; the tip should no longer be shown.
|
||||
await driver.findContent('.test-dm-workspace', /Home/).click();
|
||||
await gu.waitForDocMenuToLoad();
|
||||
await assertPromptTitle(null);
|
||||
});
|
||||
});
|
||||
|
||||
it(`should stop showing tips if "Don't show tips" is checked`, async function() {
|
||||
// Log in as a new user who hasn't seen any tips yet.
|
||||
session = await gu.session().user('user2').login({showTips: true});
|
||||
docId = await session.tempNewDoc(cleanup, 'BehavioralPromptsDontShowTips');
|
||||
await gu.loadDoc(`/doc/${docId}`);
|
||||
|
||||
// Check "Don't show tips" in the Reference Columns tip and dismiss it.
|
||||
await gu.setType(/Reference$/);
|
||||
await gu.scrollPanel(false);
|
||||
await driver.findWait('.test-behavioral-prompt-dont-show-tips', 1000).click();
|
||||
await gu.dismissBehavioralPrompts();
|
||||
|
||||
// Now visit Raw Data and check that its tip isn't shown.
|
||||
await driver.find('.test-tools-raw').click();
|
||||
await assertPromptTitle(null);
|
||||
});
|
||||
|
||||
describe('when welcome tour is active', function() {
|
||||
before(async () => {
|
||||
const welcomeTourSession = await gu.session().user('user3').login({
|
||||
isFirstLogin: false,
|
||||
freshAccount: true,
|
||||
showTips: true,
|
||||
});
|
||||
await welcomeTourSession.tempNewDoc(cleanup, 'BehavioralPromptsWelcomeTour');
|
||||
});
|
||||
|
||||
it('should not be shown', async function() {
|
||||
assert.isTrue(await driver.find('.test-onboarding-close').isDisplayed());
|
||||
// The forms announcement is normally shown here.
|
||||
await assertPromptTitle(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when in a tutorial', function() {
|
||||
gu.withEnvironmentSnapshot({'GRIST_UI_FEATURES': 'tutorials'});
|
||||
|
||||
before(async () => {
|
||||
const tutorialSession = await gu.session().user('user3').login({
|
||||
showTips: true,
|
||||
});
|
||||
const doc = await tutorialSession.tempDoc(cleanup, 'DocTutorial.grist', {load: false});
|
||||
const api = tutorialSession.createHomeApi();
|
||||
await api.updateDoc(doc.id, {type: 'tutorial'});
|
||||
await tutorialSession.loadDoc(`/doc/${doc.id}`);
|
||||
});
|
||||
|
||||
it('should not be shown', async function() {
|
||||
// The forms announcement is normally shown here.
|
||||
await assertPromptTitle(null);
|
||||
await driver.find('.test-floating-popup-minimize-maximize').click();
|
||||
await gu.toggleSidePanel('right', 'open');
|
||||
await driver.find('.test-right-tab-field').click();
|
||||
await driver.find('.test-fbuilder-type-select').click();
|
||||
await assertPromptTitle(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
async function assertPromptTitle(title: string | null) {
|
||||
if (title === null) {
|
||||
await gu.waitToPass(async () => {
|
||||
assert.equal(await driver.find('.test-behavioral-prompt').isPresent(), false);
|
||||
});
|
||||
} else {
|
||||
await gu.waitToPass(async () => {
|
||||
assert.equal(await driver.find('.test-behavioral-prompt-title').getText(), title);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -898,6 +898,20 @@ describe('FormView', function() {
|
||||
assert.deepEqual(await readLabels(), ['A', 'B', 'C', 'D']);
|
||||
assert.equal(await element('Section', 1).element('label', 4).getText(), 'D');
|
||||
|
||||
// Make sure that deleting the section also hides its fields and unmaps them.
|
||||
await element('Section').element('Paragraph', 1).click();
|
||||
await gu.sendKeys(Key.ESCAPE, Key.UP, Key.DELETE);
|
||||
await gu.waitForServer();
|
||||
assert.equal(await elementCount('Section'), 0);
|
||||
assert.deepEqual(await readLabels(), []);
|
||||
await gu.openWidgetPanel();
|
||||
assert.deepEqual(await hiddenColumns(), ['A', 'B', 'C', 'Choice', 'D']);
|
||||
|
||||
await gu.undo();
|
||||
assert.equal(await elementCount('Section'), 1);
|
||||
assert.deepEqual(await readLabels(), ['A', 'B', 'C', 'D']);
|
||||
assert.deepEqual(await hiddenColumns(), ['Choice']);
|
||||
|
||||
await revert();
|
||||
assert.deepEqual(await readLabels(), ['A', 'B', 'C']);
|
||||
});
|
||||
@@ -981,6 +995,31 @@ describe('FormView', function() {
|
||||
assert.equal(await element('column', 2).element('label').getText(), 'D');
|
||||
assert.equal(await element('column', 3).type(), 'Placeholder');
|
||||
|
||||
// Add a second question column.
|
||||
await element('Columns').element(`Placeholder`, 1).click();
|
||||
await clickMenu('Text');
|
||||
await gu.waitForServer();
|
||||
|
||||
// Delete the column and make sure both questions get deleted.
|
||||
await element('Columns').element('Field', 1).click();
|
||||
await gu.sendKeys(Key.ESCAPE, Key.UP, Key.DELETE);
|
||||
await gu.waitForServer();
|
||||
assert.deepEqual(await readLabels(), ['A', 'B', 'C']);
|
||||
await gu.openWidgetPanel();
|
||||
assert.deepEqual(await hiddenColumns(), ['Choice', 'D', 'E']);
|
||||
|
||||
// Undo and check everything reverted correctly.
|
||||
await gu.undo();
|
||||
assert.deepEqual(await readLabels(), ['A', 'B', 'C', 'E', 'D']);
|
||||
assert.equal(await elementCount('column'), 3);
|
||||
assert.equal(await element('column', 1).type(), 'Field');
|
||||
assert.equal(await element('column', 1).element('label').getText(), 'E');
|
||||
assert.equal(await element('column', 2).type(), 'Field');
|
||||
assert.equal(await element('column', 2).element('label').getText(), 'D');
|
||||
assert.equal(await element('column', 3).type(), 'Placeholder');
|
||||
assert.deepEqual(await hiddenColumns(), ['Choice']);
|
||||
await gu.undo();
|
||||
|
||||
// There was a bug with paragraph and columns.
|
||||
// Add a paragraph to first placeholder.
|
||||
await element('Columns').element(`Placeholder`, 1).click();
|
||||
|
||||
@@ -17,6 +17,7 @@ describe('GridViewNewColumnMenu', function () {
|
||||
session = await gu.session().login({showTips:true});
|
||||
api = session.createHomeApi();
|
||||
docId = await session.tempNewDoc(cleanup, 'ColumnMenu');
|
||||
await gu.dismissBehavioralPrompts();
|
||||
|
||||
// Add a table that will be used for lookups.
|
||||
await gu.sendActions([
|
||||
@@ -77,6 +78,7 @@ describe('GridViewNewColumnMenu', function () {
|
||||
it('should show rename menu after a new column click', async function () {
|
||||
await clickAddColumn();
|
||||
await driver.findWait('.test-new-columns-menu-add-new', STANDARD_WAITING_TIME).click();
|
||||
await gu.waitForServer();
|
||||
await driver.findWait('.test-column-title-popup', STANDARD_WAITING_TIME, 'rename menu is not present');
|
||||
await closeAddColumnMenu();
|
||||
});
|
||||
@@ -204,29 +206,28 @@ describe('GridViewNewColumnMenu', function () {
|
||||
await driver.findWait('.test-new-columns-menu-add-with-type-submenu', STANDARD_WAITING_TIME);
|
||||
// popup should not be showed
|
||||
assert.isFalse(await driver.find('.test-behavioral-prompt').isPresent());
|
||||
await gu.disableTips(session.email);
|
||||
await closeAddColumnMenu();
|
||||
});
|
||||
|
||||
for (const option of optionsToBeDisplayed) {
|
||||
it(`should allow to select column type ${option.type}`, async function () {
|
||||
// open add new colum menu
|
||||
await clickAddColumn();
|
||||
// select "Add Column With type" option
|
||||
await driver.findWait('.test-new-columns-menu-add-with-type', STANDARD_WAITING_TIME).click();
|
||||
// wait for submenu to appear
|
||||
await driver.findWait('.test-new-columns-menu-add-with-type-submenu', STANDARD_WAITING_TIME);
|
||||
// check if it is present in the menu
|
||||
const element = await driver.findWait(
|
||||
`.test-new-columns-menu-add-${option.testClass}`.toLowerCase(),
|
||||
100,
|
||||
`${option.type} option is not present`);
|
||||
// click on the option and check if column is added with a proper type
|
||||
await element.click();
|
||||
await gu.waitForServer();//discard rename menu
|
||||
it(`should allow to select column type ${option.type}`, async function () {
|
||||
// open add new colum menu
|
||||
await clickAddColumn();
|
||||
// select "Add Column With type" option
|
||||
await driver.findWait('.test-new-columns-menu-add-with-type', STANDARD_WAITING_TIME).click();
|
||||
// wait for submenu to appear
|
||||
await driver.findWait('.test-new-columns-menu-add-with-type-submenu', STANDARD_WAITING_TIME);
|
||||
// check if it is present in the menu
|
||||
const element = await driver.findWait(
|
||||
`.test-new-columns-menu-add-${option.testClass}`.toLowerCase(),
|
||||
100,
|
||||
`${option.type} option is not present`);
|
||||
// click on the option and check if column is added with a proper type
|
||||
await element.click();
|
||||
await gu.waitForServer();
|
||||
//discard rename menu
|
||||
await driver.findWait('.test-column-title-close', STANDARD_WAITING_TIME).click();
|
||||
//check if new column is present
|
||||
|
||||
await gu.selectColumn('D');
|
||||
await gu.openColumnPanel();
|
||||
const type = await gu.getType();
|
||||
@@ -255,14 +256,11 @@ describe('GridViewNewColumnMenu', function () {
|
||||
`${optionsTriggeringMenu.type} option is not present`);
|
||||
// click on the option and check if column is added with a proper type
|
||||
await element.click();
|
||||
await gu.waitForServer();
|
||||
//discard rename menu
|
||||
await driver.findWait('.test-column-title-close', STANDARD_WAITING_TIME).click();
|
||||
await gu.waitForServer();
|
||||
//check if left menu is opened on column section
|
||||
//check if right menu is opened on column section
|
||||
assert.isTrue(await driver.findWait('.test-right-tab-field', 1000).isDisplayed());
|
||||
|
||||
await gu.disableTips(session.email);
|
||||
await gu.dismissBehavioralPrompts();
|
||||
await gu.toggleSidePanel("right", "close");
|
||||
await gu.undo(1);
|
||||
});
|
||||
@@ -287,9 +285,9 @@ describe('GridViewNewColumnMenu', function () {
|
||||
`${optionsTriggeringMenu.type} option is not present`);
|
||||
// click on the option and check if column is added with a proper type
|
||||
await element.click();
|
||||
await gu.waitForServer();
|
||||
//discard rename menu
|
||||
await driver.findWait('.test-column-title-close', STANDARD_WAITING_TIME).click();
|
||||
await gu.waitForServer();
|
||||
//check if referenceColumnsConfig is present
|
||||
await gu.waitToPass(async ()=> assert.isTrue(
|
||||
await driver.findContentWait(
|
||||
@@ -299,8 +297,6 @@ describe('GridViewNewColumnMenu', function () {
|
||||
).isDisplayed()
|
||||
), 5000);
|
||||
await gu.dismissBehavioralPrompts();
|
||||
await gu.disableTips(session.email);
|
||||
|
||||
await gu.toggleSidePanel("right", "close");
|
||||
await gu.undo(1);
|
||||
});
|
||||
@@ -328,14 +324,11 @@ describe('GridViewNewColumnMenu', function () {
|
||||
`${optionsTriggeringMenu.type} option is not present`);
|
||||
// click on the option and check if column is added with a proper type
|
||||
await element.click();
|
||||
await gu.waitForServer();
|
||||
//discard rename menu
|
||||
await driver.findWait('.test-column-title-close', STANDARD_WAITING_TIME).click();
|
||||
await gu.waitForServer();
|
||||
//check if left menu is opened on column section
|
||||
//check if right menu is opened on column section
|
||||
assert.isFalse(await driver.find('.test-right-tab-field').isPresent());
|
||||
|
||||
await gu.disableTips(session.email);
|
||||
await gu.dismissBehavioralPrompts();
|
||||
await gu.toggleSidePanel("right", "close");
|
||||
await gu.undo(1);
|
||||
});
|
||||
@@ -381,10 +374,10 @@ describe('GridViewNewColumnMenu', function () {
|
||||
await clickAddColumn();
|
||||
// select "create formula column" option
|
||||
await driver.findWait('.test-new-columns-menu-add-formula', STANDARD_WAITING_TIME).click();
|
||||
// there should not be a rename poup
|
||||
assert.isFalse(await driver.find('test-column-title-popup').isPresent());
|
||||
//check if new column is present
|
||||
await gu.waitForServer();
|
||||
// there should not be a rename poup
|
||||
assert.isFalse(await driver.find('test-column-title-popup').isPresent());
|
||||
// check if editor popup is opened
|
||||
await driver.findWait('.test-floating-editor-popup', 200, 'Editor popup is not present');
|
||||
// write some formula
|
||||
|
||||
Reference in New Issue
Block a user