mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Forms Improvements
Summary: - Forms now have a reset button. - Choice and Reference fields in forms now have an improved select menu. - Formula and attachments column types are no longer mappable or visible in forms. - Fields in a form widget are now removed if their column is deleted. - The preview button in a published form widget has been replaced with a view button. It now opens the published form in a new tab. - A new share menu for published form widgets, with options to copy a link or embed code. - Forms can now have multiple sections. - Form widgets now indicate when publishing is unavailable (e.g. in forks or unsaved documents). - General improvements to form styling. Test Plan: Browser tests. Reviewers: jarek Reviewed By: jarek Subscribers: paulfitz Differential Revision: https://phab.getgrist.com/D4203
This commit is contained in:
@@ -37,7 +37,7 @@ describe('ACIndex', function() {
|
||||
it('should find items with matching words', function() {
|
||||
const items: ACItem[] = ["blue", "dark red", "reddish", "red", "orange", "yellow", "radical green"].map(
|
||||
c => ({cleanText: c}));
|
||||
const acIndex = new ACIndexImpl(items, 5);
|
||||
const acIndex = new ACIndexImpl(items, {maxResults: 5});
|
||||
assert.deepEqual(acIndex.search("red").items.map((item) => item.cleanText),
|
||||
["red", "reddish", "dark red", "radical green", "blue"]);
|
||||
});
|
||||
@@ -48,7 +48,7 @@ describe('ACIndex', function() {
|
||||
assert.deepEqual(acResult.items, colors);
|
||||
assert.deepEqual(acResult.selectIndex, -1);
|
||||
|
||||
acResult = new ACIndexImpl(colors, 3).search("");
|
||||
acResult = new ACIndexImpl(colors, {maxResults: 3}).search("");
|
||||
assert.deepEqual(acResult.items, colors.slice(0, 3));
|
||||
assert.deepEqual(acResult.selectIndex, -1);
|
||||
|
||||
@@ -161,7 +161,7 @@ describe('ACIndex', function() {
|
||||
});
|
||||
|
||||
it('should limit results to maxResults', function() {
|
||||
const acIndex = new ACIndexImpl(colors, 3);
|
||||
const acIndex = new ACIndexImpl(colors, {maxResults: 3});
|
||||
let acResult: ACResults<TestACItem>;
|
||||
|
||||
acResult = acIndex.search("red");
|
||||
@@ -247,7 +247,7 @@ describe('ACIndex', function() {
|
||||
});
|
||||
|
||||
it('should return a useful highlight function', function() {
|
||||
const acIndex = new ACIndexImpl(colors, 3);
|
||||
const acIndex = new ACIndexImpl(colors, {maxResults: 3});
|
||||
let acResult: ACResults<TestACItem>;
|
||||
|
||||
// Here we split the items' (uncleaned) text with the returned highlightFunc. The values at
|
||||
@@ -267,7 +267,7 @@ describe('ACIndex', function() {
|
||||
[["Blue"], ["Dark Red"], ["Reddish"]]);
|
||||
|
||||
// Try some messier cases.
|
||||
const acIndex2 = new ACIndexImpl(messy, 6);
|
||||
const acIndex2 = new ACIndexImpl(messy, {maxResults: 6});
|
||||
acResult = acIndex2.search("#r");
|
||||
assert.deepEqual(acResult.items.map(i => acResult.highlightFunc(i.text)),
|
||||
[["#", "r", "ed"], [" ", "R", "ED "], ["", "r", "ed"], ["", "r", "ead "],
|
||||
@@ -280,7 +280,9 @@ describe('ACIndex', function() {
|
||||
});
|
||||
|
||||
it('should highlight multi-byte unicode', function() {
|
||||
const acIndex = new ACIndexImpl(['Lorem ipsum 𝌆 dolor sit ameͨ͆t.', "mañana", "Москва"].map(makeItem), 3);
|
||||
const acIndex = new ACIndexImpl(['Lorem ipsum 𝌆 dolor sit ameͨ͆t.', "mañana", "Москва"].map(makeItem), {
|
||||
maxResults: 3,
|
||||
});
|
||||
let acResult: ACResults<TestACItem> = acIndex.search("mañ моск am");
|
||||
assert.deepEqual(acResult.items.map(i => acResult.highlightFunc(i.text)),
|
||||
[["", "Моск", "ва"], ["", "mañ", "ana"], ["Lorem ipsum 𝌆 dolor sit ", "am", "eͨ͆t."]]);
|
||||
@@ -345,7 +347,7 @@ describe('ACIndex', function() {
|
||||
// tslint:disable:no-console
|
||||
|
||||
it('main algorithm', function() {
|
||||
const [buildTime, acIndex] = repeat(10, () => new ACIndexImpl(items, 100));
|
||||
const [buildTime, acIndex] = repeat(10, () => new ACIndexImpl(items, {maxResults: 100}));
|
||||
console.log(`Time to build index (${items.length} items): ${buildTime} ms`);
|
||||
|
||||
const [searchTime, result] = repeat(10, () => acIndex.search("YORK"));
|
||||
|
||||
@@ -20,29 +20,6 @@ describe('FormView', function() {
|
||||
|
||||
afterEach(() => gu.checkForErrors());
|
||||
|
||||
/**
|
||||
* Adds a temporary textarea to the document for pasting the contents of
|
||||
* the clipboard.
|
||||
*
|
||||
* Used to test copying of form URLs to the clipboard.
|
||||
*/
|
||||
function createClipboardTextArea() {
|
||||
const textArea = document.createElement('textarea');
|
||||
textArea.style.position = 'absolute';
|
||||
textArea.style.top = '0';
|
||||
textArea.style.height = '2rem';
|
||||
textArea.style.width = '16rem';
|
||||
textArea.id = 'clipboardText';
|
||||
window.document.body.appendChild(textArea);
|
||||
}
|
||||
|
||||
function removeClipboardTextArea() {
|
||||
const textArea = document.getElementById('clipboardText');
|
||||
if (textArea) {
|
||||
window.document.body.removeChild(textArea);
|
||||
}
|
||||
}
|
||||
|
||||
async function createFormWith(type: string, more = false) {
|
||||
await gu.addNewSection('Form', 'Table1');
|
||||
|
||||
@@ -69,8 +46,11 @@ describe('FormView', function() {
|
||||
|
||||
// Now open the form in external window.
|
||||
await clipboard.lockAndPerform(async (cb) => {
|
||||
await driver.find(`.test-forms-link`).click();
|
||||
const shareButton = await driver.find(`.test-forms-share`);
|
||||
await gu.scrollIntoView(shareButton);
|
||||
await shareButton.click();
|
||||
await gu.waitForServer();
|
||||
await driver.findWait('.test-forms-link', 1000).click();
|
||||
await gu.waitToPass(async () => assert.match(
|
||||
await driver.find('.test-tooltip').getText(), /Link copied to clipboard/), 1000);
|
||||
await driver.find('#clipboardText').click();
|
||||
@@ -121,12 +101,9 @@ describe('FormView', function() {
|
||||
const session = await gu.session().login();
|
||||
docId = await session.tempNewDoc(cleanup);
|
||||
api = session.createHomeApi();
|
||||
await driver.executeScript(createClipboardTextArea);
|
||||
});
|
||||
|
||||
after(async function() {
|
||||
await driver.executeScript(removeClipboardTextArea);
|
||||
});
|
||||
gu.withClipboardTextArea();
|
||||
|
||||
it('updates creator panel when navigated away', async function() {
|
||||
// Add 2 new pages.
|
||||
@@ -186,6 +163,12 @@ describe('FormView', function() {
|
||||
await gu.onNewTab(async () => {
|
||||
await driver.get(formUrl);
|
||||
await driver.findWait('input[name="D"]', 2000).click();
|
||||
await gu.sendKeys('Hello');
|
||||
assert.equal(await driver.find('input[name="D"]').value(), 'Hello');
|
||||
await driver.find('.test-form-reset').click();
|
||||
await driver.find('.test-modal-confirm').click();
|
||||
assert.equal(await driver.find('input[name="D"]').value(), '');
|
||||
await driver.find('input[name="D"]').click();
|
||||
await gu.sendKeys('Hello World');
|
||||
await driver.find('input[type="submit"]').click();
|
||||
await waitForConfirm();
|
||||
@@ -201,6 +184,12 @@ describe('FormView', function() {
|
||||
await gu.onNewTab(async () => {
|
||||
await driver.get(formUrl);
|
||||
await driver.findWait('input[name="D"]', 2000).click();
|
||||
await gu.sendKeys('1983');
|
||||
assert.equal(await driver.find('input[name="D"]').value(), '1983');
|
||||
await driver.find('.test-form-reset').click();
|
||||
await driver.find('.test-modal-confirm').click();
|
||||
assert.equal(await driver.find('input[name="D"]').value(), '');
|
||||
await driver.find('input[name="D"]').click();
|
||||
await gu.sendKeys('1984');
|
||||
await driver.find('input[type="submit"]').click();
|
||||
await waitForConfirm();
|
||||
@@ -216,9 +205,13 @@ describe('FormView', function() {
|
||||
await gu.onNewTab(async () => {
|
||||
await driver.get(formUrl);
|
||||
await driver.findWait('input[name="D"]', 2000).click();
|
||||
await driver.executeScript(
|
||||
() => (document.querySelector('input[name="D"]') as HTMLInputElement).value = '2000-01-01'
|
||||
);
|
||||
await gu.sendKeys('01011999');
|
||||
assert.equal(await driver.find('input[name="D"]').getAttribute('value'), '1999-01-01');
|
||||
await driver.find('.test-form-reset').click();
|
||||
await driver.find('.test-modal-confirm').click();
|
||||
assert.equal(await driver.find('input[name="D"]').getAttribute('value'), '');
|
||||
await driver.find('input[name="D"]').click();
|
||||
await gu.sendKeys('01012000');
|
||||
await driver.find('input[type="submit"]').click();
|
||||
await waitForConfirm();
|
||||
});
|
||||
@@ -239,21 +232,30 @@ describe('FormView', function() {
|
||||
await gu.choicesEditor.save();
|
||||
await gu.toggleSidePanel('right', 'close');
|
||||
|
||||
// We need to press preview, as form is not saved yet.
|
||||
// We need to press view, as form is not saved yet.
|
||||
await gu.scrollActiveViewTop();
|
||||
await gu.waitToPass(async () => {
|
||||
assert.isTrue(await driver.find('.test-forms-preview').isDisplayed());
|
||||
assert.isTrue(await driver.find('.test-forms-view').isDisplayed());
|
||||
});
|
||||
// We are in a new window.
|
||||
await gu.onNewTab(async () => {
|
||||
await driver.get(formUrl);
|
||||
const select = await driver.findWait('select[name="D"]', 2000);
|
||||
await driver.findWait('select[name="D"]', 2000);
|
||||
// Make sure options are there.
|
||||
assert.deepEqual(
|
||||
await driver.findAll('select[name="D"] option', e => e.getText()), ['— Choose —', 'Foo', 'Bar', 'Baz']
|
||||
await driver.findAll('select[name="D"] option', e => e.getText()), ['Select...', 'Foo', 'Bar', 'Baz']
|
||||
);
|
||||
await select.click();
|
||||
await driver.find("option[value='Bar']").click();
|
||||
await driver.find('.test-form-search-select').click();
|
||||
assert.deepEqual(
|
||||
await driver.findAll('.test-sd-searchable-list-item', e => e.getText()), ['Select...', 'Foo', 'Bar', 'Baz']
|
||||
);
|
||||
await gu.sendKeys('Baz', Key.ENTER);
|
||||
assert.equal(await driver.find('select[name="D"]').value(), 'Baz');
|
||||
await driver.find('.test-form-reset').click();
|
||||
await driver.find('.test-modal-confirm').click();
|
||||
assert.equal(await driver.find('select[name="D"]').value(), '');
|
||||
await driver.find('.test-form-search-select').click();
|
||||
await driver.findContent('.test-sd-searchable-list-item', 'Bar').click();
|
||||
await driver.find('input[type="submit"]').click();
|
||||
await waitForConfirm();
|
||||
});
|
||||
@@ -267,6 +269,12 @@ describe('FormView', function() {
|
||||
await gu.onNewTab(async () => {
|
||||
await driver.get(formUrl);
|
||||
await driver.findWait('input[name="D"]', 2000).click();
|
||||
await gu.sendKeys('1983');
|
||||
assert.equal(await driver.find('input[name="D"]').value(), '1983');
|
||||
await driver.find('.test-form-reset').click();
|
||||
await driver.find('.test-modal-confirm').click();
|
||||
assert.equal(await driver.find('input[name="D"]').value(), '');
|
||||
await driver.find('input[name="D"]').click();
|
||||
await gu.sendKeys('1984');
|
||||
await driver.find('input[type="submit"]').click();
|
||||
await waitForConfirm();
|
||||
@@ -282,6 +290,11 @@ describe('FormView', function() {
|
||||
await gu.onNewTab(async () => {
|
||||
await driver.get(formUrl);
|
||||
await driver.findWait('input[name="D"]', 2000).findClosest("label").click();
|
||||
assert.equal(await driver.find('input[name="D"]').getAttribute('checked'), 'true');
|
||||
await driver.find('.test-form-reset').click();
|
||||
await driver.find('.test-modal-confirm').click();
|
||||
assert.equal(await driver.find('input[name="D"]').getAttribute('checked'), null);
|
||||
await driver.find('input[name="D"]').findClosest("label").click();
|
||||
await driver.find('input[type="submit"]').click();
|
||||
await waitForConfirm();
|
||||
});
|
||||
@@ -314,7 +327,12 @@ describe('FormView', function() {
|
||||
// We are in a new window.
|
||||
await gu.onNewTab(async () => {
|
||||
await driver.get(formUrl);
|
||||
await driver.findWait('input[name="D[]"][value="Foo"]', 2000).click();
|
||||
await driver.findWait('input[name="D[]"][value="Bar"]', 2000).click();
|
||||
assert.equal(await driver.find('input[name="D[]"][value="Bar"]').getAttribute('checked'), 'true');
|
||||
await driver.find('.test-form-reset').click();
|
||||
await driver.find('.test-modal-confirm').click();
|
||||
assert.equal(await driver.find('input[name="D[]"][value="Bar"]').getAttribute('checked'), null);
|
||||
await driver.find('input[name="D[]"][value="Foo"]').click();
|
||||
await driver.find('input[name="D[]"][value="Baz"]').click();
|
||||
await driver.find('input[type="submit"]').click();
|
||||
await waitForConfirm();
|
||||
@@ -339,17 +357,26 @@ describe('FormView', function() {
|
||||
// We are in a new window.
|
||||
await gu.onNewTab(async () => {
|
||||
await driver.get(formUrl);
|
||||
const select = await driver.findWait('select[name="D"]', 2000);
|
||||
await driver.findWait('select[name="D"]', 2000);
|
||||
assert.deepEqual(
|
||||
await driver.findAll('select[name="D"] option', e => e.getText()),
|
||||
['— Choose —', ...['Bar', 'Baz', 'Foo']]
|
||||
['Select...', ...['Bar', 'Baz', 'Foo']]
|
||||
);
|
||||
assert.deepEqual(
|
||||
await driver.findAll('select[name="D"] option', e => e.value()),
|
||||
['', ...['2', '3', '1']]
|
||||
);
|
||||
await select.click();
|
||||
await driver.find('option[value="2"]').click();
|
||||
await driver.find('.test-form-search-select').click();
|
||||
assert.deepEqual(
|
||||
await driver.findAll('.test-sd-searchable-list-item', e => e.getText()), ['Select...', 'Bar', 'Baz', 'Foo']
|
||||
);
|
||||
await gu.sendKeys('Baz', Key.ENTER);
|
||||
assert.equal(await driver.find('select[name="D"]').value(), '3');
|
||||
await driver.find('.test-form-reset').click();
|
||||
await driver.find('.test-modal-confirm').click();
|
||||
assert.equal(await driver.find('select[name="D"]').value(), '');
|
||||
await driver.find('.test-form-search-select').click();
|
||||
await driver.findContent('.test-sd-searchable-list-item', 'Bar').click();
|
||||
await driver.find('input[type="submit"]').click();
|
||||
await waitForConfirm();
|
||||
});
|
||||
@@ -379,11 +406,16 @@ describe('FormView', function() {
|
||||
// We are in a new window.
|
||||
await gu.onNewTab(async () => {
|
||||
await driver.get(formUrl);
|
||||
await driver.findWait('input[name="D[]"][value="1"]', 2000).click();
|
||||
await driver.find('input[name="D[]"][value="2"]').click();
|
||||
assert.equal(await driver.find('label:has(input[name="D[]"][value="1"])').getText(), 'Foo');
|
||||
assert.equal(await driver.findWait('label:has(input[name="D[]"][value="1"])', 2000).getText(), 'Foo');
|
||||
assert.equal(await driver.find('label:has(input[name="D[]"][value="2"])').getText(), 'Bar');
|
||||
assert.equal(await driver.find('label:has(input[name="D[]"][value="3"])').getText(), 'Baz');
|
||||
await driver.find('input[name="D[]"][value="1"]').click();
|
||||
assert.equal(await driver.find('input[name="D[]"][value="1"]').getAttribute('checked'), 'true');
|
||||
await driver.find('.test-form-reset').click();
|
||||
await driver.find('.test-modal-confirm').click();
|
||||
assert.equal(await driver.find('input[name="D[]"][value="1"]').getAttribute('checked'), null);
|
||||
await driver.find('input[name="D[]"][value="1"]').click();
|
||||
await driver.find('input[name="D[]"][value="2"]').click();
|
||||
await driver.find('input[type="submit"]').click();
|
||||
await waitForConfirm();
|
||||
});
|
||||
@@ -402,12 +434,22 @@ describe('FormView', function() {
|
||||
|
||||
// Temporarily make A a formula column.
|
||||
await gu.sendActions([
|
||||
['AddRecord', 'Table1', null, {A: 'Foo'}],
|
||||
['UpdateRecord', '_grist_Tables_column', 2, {formula: '"hello"', isFormula: true}],
|
||||
['ModifyColumn', 'Table1', 'A', {formula: '"hello"', isFormula: true}],
|
||||
]);
|
||||
assert.deepEqual(await api.getTable(docId, 'Table1').then(t => t.A), ['hello']);
|
||||
|
||||
// Check that A is excluded from the form, and we can still submit it.
|
||||
// Check that A is hidden in the form editor.
|
||||
await gu.waitToPass(async () => assert.deepEqual(await readLabels(), ['B', 'C', 'D']));
|
||||
await gu.openWidgetPanel('widget');
|
||||
assert.deepEqual(
|
||||
await driver.findAll('.test-vfc-visible-field', (e) => e.getText()),
|
||||
['B', 'C', 'D']
|
||||
);
|
||||
assert.deepEqual(
|
||||
await driver.findAll('.test-vfc-hidden-field', (e) => e.getText()),
|
||||
[]
|
||||
);
|
||||
|
||||
// Check that A is excluded from the published form.
|
||||
await gu.onNewTab(async () => {
|
||||
await driver.get(formUrl);
|
||||
await driver.findWait('input[name="D"]', 2000).click();
|
||||
@@ -418,15 +460,78 @@ describe('FormView', function() {
|
||||
});
|
||||
|
||||
// Make sure we see the new record.
|
||||
await expectInD(['', 'Hello World']);
|
||||
await expectInD(['Hello World']);
|
||||
|
||||
// And check that A was not modified.
|
||||
assert.deepEqual(await api.getTable(docId, 'Table1').then(t => t.A), ['hello', 'hello']);
|
||||
assert.deepEqual(await api.getTable(docId, 'Table1').then(t => t.A), ['hello']);
|
||||
|
||||
// Revert A and check that it's visible again in the editor.
|
||||
await gu.sendActions([
|
||||
['RemoveRecord', 'Table1', 1],
|
||||
['UpdateRecord', '_grist_Tables_column', 2, {formula: '', isFormula: false}],
|
||||
['ModifyColumn', 'Table1', 'A', {formula: '', isFormula: false}],
|
||||
]);
|
||||
await gu.waitToPass(async () => assert.deepEqual(await readLabels(), ['A', 'B', 'C', 'D']));
|
||||
assert.deepEqual(
|
||||
await driver.findAll('.test-vfc-visible-field', (e) => e.getText()),
|
||||
['A', 'B', 'C', 'D']
|
||||
);
|
||||
assert.deepEqual(
|
||||
await driver.findAll('.test-vfc-hidden-field', (e) => e.getText()),
|
||||
[]
|
||||
);
|
||||
|
||||
await removeForm();
|
||||
});
|
||||
|
||||
it('excludes attachment fields from forms', async function() {
|
||||
const formUrl = await createFormWith('Text');
|
||||
|
||||
// Temporarily make A an attachments column.
|
||||
await gu.sendActions([
|
||||
['ModifyColumn', 'Table1', 'A', {type: 'Attachments'}],
|
||||
]);
|
||||
|
||||
// Check that A is hidden in the form editor.
|
||||
await gu.waitToPass(async () => assert.deepEqual(await readLabels(), ['B', 'C', 'D']));
|
||||
await gu.openWidgetPanel('widget');
|
||||
assert.deepEqual(
|
||||
await driver.findAll('.test-vfc-visible-field', (e) => e.getText()),
|
||||
['B', 'C', 'D']
|
||||
);
|
||||
assert.deepEqual(
|
||||
await driver.findAll('.test-vfc-hidden-field', (e) => e.getText()),
|
||||
[]
|
||||
);
|
||||
|
||||
// Check that A is excluded from the published form.
|
||||
await gu.onNewTab(async () => {
|
||||
await driver.get(formUrl);
|
||||
await driver.findWait('input[name="D"]', 2000).click();
|
||||
await gu.sendKeys('Hello World');
|
||||
assert.isFalse(await driver.find('input[name="A"]').isPresent());
|
||||
await driver.find('input[type="submit"]').click();
|
||||
await waitForConfirm();
|
||||
});
|
||||
|
||||
// Make sure we see the new record.
|
||||
await expectInD(['Hello World']);
|
||||
|
||||
// And check that A was not modified.
|
||||
assert.deepEqual(await api.getTable(docId, 'Table1').then(t => t.A), [null]);
|
||||
|
||||
// Revert A and check that it's visible again in the editor.
|
||||
await gu.sendActions([
|
||||
['ModifyColumn', 'Table1', 'A', {type: 'Text'}],
|
||||
]);
|
||||
await gu.waitToPass(async () => assert.deepEqual(await readLabels(), ['A', 'B', 'C', 'D']));
|
||||
assert.deepEqual(
|
||||
await driver.findAll('.test-vfc-visible-field', (e) => e.getText()),
|
||||
['A', 'B', 'C', 'D']
|
||||
);
|
||||
assert.deepEqual(
|
||||
await driver.findAll('.test-vfc-hidden-field', (e) => e.getText()),
|
||||
[]
|
||||
);
|
||||
|
||||
await removeForm();
|
||||
});
|
||||
|
||||
@@ -851,28 +956,33 @@ describe('FormView', function() {
|
||||
checkFieldInMore('Reference List');
|
||||
|
||||
const testStruct = (type: string, existing = 0) => {
|
||||
it(`can add structure ${type} element`, async function() {
|
||||
async function doTestStruct(menuLabel?: string) {
|
||||
assert.equal(await elementCount(type), existing);
|
||||
await plusButton().click();
|
||||
await clickMenu(type);
|
||||
await clickMenu(menuLabel ?? type);
|
||||
await gu.waitForServer();
|
||||
assert.equal(await elementCount(type), existing + 1);
|
||||
await gu.undo();
|
||||
assert.equal(await elementCount(type), existing);
|
||||
}
|
||||
|
||||
it(`can add structure ${type} element`, async function() {
|
||||
if (type === 'Section') {
|
||||
await doTestStruct('Insert section above');
|
||||
await doTestStruct('Insert section below');
|
||||
} else {
|
||||
await doTestStruct();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// testStruct('Section'); // There is already a section
|
||||
testStruct('Section', 1);
|
||||
testStruct('Columns');
|
||||
testStruct('Paragraph', 4);
|
||||
|
||||
it('basic section', async function() {
|
||||
const revert = await gu.begin();
|
||||
|
||||
// Adding section is disabled for now, so this test is altered to use the existing section.
|
||||
// await drop().click();
|
||||
// await clickMenu('Section');
|
||||
// await gu.waitForServer();
|
||||
assert.equal(await elementCount('Section'), 1);
|
||||
|
||||
assert.deepEqual(await readLabels(), ['A', 'B', 'C']);
|
||||
@@ -898,25 +1008,39 @@ describe('FormView', function() {
|
||||
await gu.waitForServer();
|
||||
assert.deepEqual(await readLabels(), ['A', 'D', 'B', 'C']);
|
||||
|
||||
// Make sure that it is not inside the section anymore.
|
||||
// assert.equal(await element('Section', 1).element('label').isPresent(), false);
|
||||
|
||||
await gu.undo();
|
||||
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.
|
||||
// Check that we can't delete a section if it's the only one.
|
||||
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(), []);
|
||||
assert.equal(await elementCount('Section'), 1);
|
||||
|
||||
// Add a new section below it.
|
||||
await plusButton().click();
|
||||
await clickMenu('Insert section below');
|
||||
await gu.waitForServer();
|
||||
assert.equal(await elementCount('Section'), 2);
|
||||
await plusButton(element('Section', 2)).click();
|
||||
await clickMenu('Text');
|
||||
await gu.waitForServer();
|
||||
|
||||
// Now check that we can delete the first section.
|
||||
await element('Section', 1).element('Paragraph', 1).click();
|
||||
await gu.sendKeys(Key.ESCAPE, Key.UP, Key.DELETE);
|
||||
await gu.waitForServer();
|
||||
assert.equal(await elementCount('Section'), 1);
|
||||
|
||||
// Make sure that deleting the section also hides its fields and unmaps them.
|
||||
assert.deepEqual(await readLabels(), ['E']);
|
||||
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.equal(await elementCount('Section'), 2);
|
||||
assert.deepEqual(await readLabels(), ['A', 'B', 'C', 'D', 'E']);
|
||||
assert.deepEqual(await hiddenColumns(), ['Choice']);
|
||||
|
||||
await revert();
|
||||
@@ -1243,12 +1367,9 @@ describe('FormView', function() {
|
||||
const session = await gu.session().teamSite.login();
|
||||
docId = await session.tempNewDoc(cleanup);
|
||||
api = session.createHomeApi();
|
||||
await driver.executeScript(createClipboardTextArea);
|
||||
});
|
||||
|
||||
after(async function() {
|
||||
await driver.executeScript(removeClipboardTextArea);
|
||||
});
|
||||
gu.withClipboardTextArea();
|
||||
|
||||
it('can submit a form', async function() {
|
||||
// A bug was preventing this by forcing a login redirect from the public form URL.
|
||||
@@ -1309,8 +1430,8 @@ function questionType(label: string) {
|
||||
return question(label).find('.test-forms-type').value();
|
||||
}
|
||||
|
||||
function plusButton() {
|
||||
return element('plus');
|
||||
function plusButton(parent?: WebElement) {
|
||||
return element('plus', parent);
|
||||
}
|
||||
|
||||
function drops() {
|
||||
|
||||
@@ -262,7 +262,8 @@ describe('GridViewNewColumnMenu', function () {
|
||||
// Wait for the side panel animation.
|
||||
await gu.waitForSidePanel();
|
||||
//check if right menu is opened on column section
|
||||
assert.isTrue(await driver.findWait('.test-right-tab-field', 1000).isDisplayed());
|
||||
await gu.waitForSidePanel();
|
||||
assert.isTrue(await driver.find('.test-right-tab-field').isDisplayed());
|
||||
await gu.toggleSidePanel("right", "close");
|
||||
await gu.undo(1);
|
||||
});
|
||||
|
||||
@@ -3469,6 +3469,52 @@ export async function switchToWindow(target: string) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a temporary textarea to the document for pasting the contents of
|
||||
* the clipboard.
|
||||
*/
|
||||
export async function createClipboardTextArea() {
|
||||
function createTextArea() {
|
||||
const textArea = window.document.createElement('textarea');
|
||||
textArea.style.position = 'absolute';
|
||||
textArea.style.top = '0';
|
||||
textArea.style.height = '2rem';
|
||||
textArea.style.width = '16rem';
|
||||
textArea.id = 'clipboardText';
|
||||
window.document.body.appendChild(textArea);
|
||||
}
|
||||
|
||||
await driver.executeScript(createTextArea);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the temporary textarea added by `createClipboardTextArea`.
|
||||
*/
|
||||
export async function removeClipboardTextArea() {
|
||||
function removeTextArea() {
|
||||
const textArea = window.document.getElementById('clipboardText');
|
||||
if (textArea) {
|
||||
window.document.body.removeChild(textArea);
|
||||
}
|
||||
}
|
||||
|
||||
await driver.executeScript(removeTextArea);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a temporary textarea for pasting the contents of the clipboard,
|
||||
* removing it after all tests have run.
|
||||
*/
|
||||
export function withClipboardTextArea() {
|
||||
before(async function() {
|
||||
await createClipboardTextArea();
|
||||
});
|
||||
|
||||
after(async function() {
|
||||
await removeClipboardTextArea();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns an instance of `LockableClipboard`, making sure to unlock it after
|
||||
* each test.
|
||||
|
||||
Reference in New Issue
Block a user