2024-05-29 21:55:21 +00:00
|
|
|
import {UserAPI} from 'app/common/UserAPI';
|
2024-04-26 20:34:16 +00:00
|
|
|
import {assert, driver, Key} from 'mocha-webdriver';
|
|
|
|
import * as gu from 'test/nbrowser/gristUtils';
|
|
|
|
import {setupTestSuite} from 'test/nbrowser/testUtils';
|
|
|
|
|
|
|
|
describe('DropdownConditionEditor', function () {
|
|
|
|
this.timeout(20000);
|
|
|
|
const cleanup = setupTestSuite();
|
2024-05-29 21:55:21 +00:00
|
|
|
let api: UserAPI;
|
|
|
|
let docId: string;
|
2024-04-26 20:34:16 +00:00
|
|
|
|
|
|
|
before(async () => {
|
2024-05-29 21:55:21 +00:00
|
|
|
const session = await gu.session().user('user1').login();
|
|
|
|
api = session.createHomeApi();
|
|
|
|
docId = (await session.tempDoc(cleanup, 'DropdownCondition.grist')).id;
|
|
|
|
await api.updateDocPermissions(docId, {users: {
|
|
|
|
[gu.translateUser('user2').email]: 'editors',
|
|
|
|
}});
|
|
|
|
await addUserAttributes();
|
|
|
|
await gu.openPage('Employees');
|
2024-04-26 20:34:16 +00:00
|
|
|
await gu.openColumnPanel();
|
|
|
|
});
|
|
|
|
|
|
|
|
afterEach(() => gu.checkForErrors());
|
|
|
|
|
2024-05-29 21:55:21 +00:00
|
|
|
async function addUserAttributes() {
|
|
|
|
await api.applyUserActions(docId, [
|
|
|
|
['AddTable', 'Roles', [{id: 'Email'}, {id: 'Admin', type: 'Bool'}]],
|
|
|
|
['AddRecord', 'Roles', null, {Email: gu.translateUser('user1').email, Admin: true}],
|
|
|
|
['AddRecord', 'Roles', null, {Email: gu.translateUser('user2').email, Admin: false}],
|
|
|
|
]);
|
|
|
|
await driver.find('.test-tools-access-rules').click();
|
|
|
|
await gu.waitForServer();
|
|
|
|
await driver.findContentWait('button', /Add User Attributes/, 2000).click();
|
|
|
|
const userAttrRule = await driver.find('.test-rule-userattr');
|
|
|
|
await userAttrRule.find('.test-rule-userattr-name').click();
|
|
|
|
await driver.sendKeys('Roles', Key.ENTER);
|
|
|
|
await userAttrRule.find('.test-rule-userattr-attr').click();
|
|
|
|
await driver.sendKeys('Email', Key.ENTER);
|
|
|
|
await userAttrRule.find('.test-rule-userattr-table').click();
|
|
|
|
await driver.findContent('.test-select-menu li', 'Roles').click();
|
|
|
|
await userAttrRule.find('.test-rule-userattr-col').click();
|
|
|
|
await driver.sendKeys('Email', Key.ENTER);
|
|
|
|
await driver.find('.test-rules-save').click();
|
|
|
|
await gu.waitForServer();
|
|
|
|
}
|
|
|
|
|
2024-04-26 20:34:16 +00:00
|
|
|
describe(`in choice columns`, function() {
|
2024-05-29 21:55:21 +00:00
|
|
|
before(async () => {
|
|
|
|
const session = await gu.session().user('user1').login();
|
|
|
|
await session.loadDoc(`/doc/${docId}`);
|
|
|
|
});
|
|
|
|
|
2024-04-26 20:34:16 +00:00
|
|
|
it('creates dropdown conditions', async function() {
|
|
|
|
await gu.getCell(1, 1).click();
|
2024-05-29 21:55:21 +00:00
|
|
|
await driver.find('.test-field-dropdown-condition').click();
|
2024-05-02 15:32:05 +00:00
|
|
|
await gu.waitAppFocus(false);
|
2024-05-29 21:55:21 +00:00
|
|
|
await gu.sendKeys(await gu.selectAllKey(), Key.DELETE, 'c');
|
2024-04-26 20:34:16 +00:00
|
|
|
await gu.waitToPass(async () => {
|
|
|
|
const completions = await driver.findAll('.ace_autocomplete .ace_line', el => el.getText());
|
|
|
|
assert.deepEqual(completions, [
|
|
|
|
'c\nhoice\n ',
|
|
|
|
're\nc\n.Name\n ',
|
|
|
|
're\nc\n.Role\n ',
|
|
|
|
're\nc\n.Supervisor\n ',
|
2024-05-29 21:55:21 +00:00
|
|
|
'user.A\nc\ncess\n ',
|
2024-04-26 20:34:16 +00:00
|
|
|
]);
|
|
|
|
});
|
2024-06-07 19:07:25 +00:00
|
|
|
await gu.sendKeysSlowly(['hoice not in ']);
|
|
|
|
// Attempts to reduce test flakiness by delaying input of $. Not guaranteed to do anything.
|
|
|
|
await driver.sleep(100);
|
|
|
|
await gu.sendKeys('$');
|
2024-04-26 20:34:16 +00:00
|
|
|
await gu.waitToPass(async () => {
|
2024-06-07 19:07:25 +00:00
|
|
|
// This test is sometimes flaky here. It will consistently return the wrong value, usually an array of
|
|
|
|
// empty strings. The running theory is it's an issue in Ace editor.
|
2024-04-26 20:34:16 +00:00
|
|
|
const completions = await driver.findAll('.ace_autocomplete .ace_line', el => el.getText());
|
|
|
|
assert.deepEqual(completions, [
|
|
|
|
'$\nName\n ',
|
|
|
|
'$\nRole\n ',
|
|
|
|
'$\nSupervisor\n ',
|
|
|
|
]);
|
|
|
|
});
|
|
|
|
await gu.sendKeys('Role', Key.ENTER);
|
|
|
|
await gu.waitForServer();
|
|
|
|
assert.equal(
|
|
|
|
await driver.find('.test-field-dropdown-condition').getText(),
|
|
|
|
'choice not in $Role'
|
|
|
|
);
|
|
|
|
|
|
|
|
// Check that autocomplete values are filtered.
|
|
|
|
await gu.sendKeys(Key.ENTER);
|
|
|
|
assert.deepEqual(await driver.findAll('.test-autocomplete li', (el) => el.getText()), [
|
|
|
|
'Supervisor',
|
|
|
|
]);
|
|
|
|
await gu.sendKeys(Key.ESCAPE);
|
|
|
|
await gu.getCell(1, 4).click();
|
|
|
|
await gu.sendKeys(Key.ENTER);
|
|
|
|
assert.deepEqual(await driver.findAll('.test-autocomplete li', (el) => el.getText()), [
|
|
|
|
'Trainee',
|
|
|
|
]);
|
|
|
|
await gu.sendKeys(Key.ESCAPE);
|
|
|
|
await gu.getCell(1, 6).click();
|
|
|
|
await gu.sendKeys(Key.ENTER);
|
|
|
|
assert.deepEqual(await driver.findAll('.test-autocomplete li', (el) => el.getText()), [
|
|
|
|
'Trainee',
|
|
|
|
'Supervisor',
|
|
|
|
]);
|
|
|
|
await gu.sendKeys(Key.ESCAPE);
|
|
|
|
|
|
|
|
// Change the column type to Choice List and check values are still filtered.
|
|
|
|
await gu.setType('Choice List', {apply: true});
|
|
|
|
assert.equal(
|
|
|
|
await driver.find('.test-field-dropdown-condition').getText(),
|
|
|
|
'choice not in $Role'
|
|
|
|
);
|
|
|
|
await gu.getCell(1, 4).click();
|
|
|
|
await gu.sendKeys(Key.ENTER);
|
|
|
|
assert.deepEqual(await driver.findAll('.test-autocomplete li', (el) => el.getText()), [
|
|
|
|
'Trainee',
|
|
|
|
]);
|
|
|
|
await gu.sendKeys(Key.ESCAPE);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('removes dropdown conditions', async function() {
|
|
|
|
await driver.find('.test-field-dropdown-condition').click();
|
|
|
|
await gu.sendKeys(await gu.selectAllKey(), Key.DELETE, Key.ENTER);
|
|
|
|
await gu.waitForServer();
|
|
|
|
|
|
|
|
// Check that autocomplete values are no longer filtered.
|
|
|
|
await gu.sendKeys(Key.ENTER);
|
|
|
|
assert.deepEqual(await driver.findAll('.test-autocomplete li', (el) => el.getText()), [
|
|
|
|
'Trainee',
|
|
|
|
'Supervisor',
|
|
|
|
]);
|
|
|
|
await gu.sendKeys(Key.ESCAPE);
|
|
|
|
|
|
|
|
// Change the column type back to Choice and check values are still no longer filtered.
|
|
|
|
await gu.setType('Choice', {apply: true});
|
|
|
|
assert.isFalse(await driver.find('.test-field-dropdown-condition').isPresent());
|
|
|
|
await gu.sendKeys(Key.ENTER);
|
|
|
|
assert.deepEqual(await driver.findAll('.test-autocomplete li', (el) => el.getText()), [
|
|
|
|
'Supervisor',
|
|
|
|
'Trainee',
|
|
|
|
]);
|
|
|
|
await gu.sendKeys(Key.ESCAPE);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('reports errors', async function() {
|
|
|
|
// Check syntax errors are reported, but not saved.
|
|
|
|
await driver.find('.test-field-set-dropdown-condition').click();
|
|
|
|
await gu.sendKeys('!@#$%^', Key.ENTER);
|
|
|
|
await gu.waitForServer();
|
|
|
|
assert.equal(
|
|
|
|
await driver.find('.test-field-dropdown-condition-error').getText(),
|
|
|
|
'SyntaxError invalid syntax on line 1 col 1'
|
|
|
|
);
|
|
|
|
await gu.reloadDoc();
|
|
|
|
assert.isFalse(await driver.find('.test-field-dropdown-condition-error').isPresent());
|
|
|
|
|
|
|
|
// Check compilation errors are reported and saved.
|
|
|
|
await driver.find('.test-field-set-dropdown-condition').click();
|
|
|
|
await gu.sendKeys('foo', Key.ENTER);
|
|
|
|
await gu.waitForServer();
|
|
|
|
assert.equal(
|
|
|
|
await driver.find('.test-field-dropdown-condition-error').getText(),
|
|
|
|
"Unknown variable 'foo'"
|
|
|
|
);
|
|
|
|
await gu.reloadDoc();
|
|
|
|
assert.equal(
|
|
|
|
await driver.find('.test-field-dropdown-condition-error').getText(),
|
|
|
|
"Unknown variable 'foo'"
|
|
|
|
);
|
|
|
|
|
|
|
|
// Check that the autocomplete dropdown also reports an error.
|
|
|
|
await gu.sendKeys(Key.ENTER);
|
|
|
|
assert.equal(
|
|
|
|
await driver.find('.test-autocomplete-no-items-message').getText(),
|
|
|
|
'Error in dropdown condition'
|
|
|
|
);
|
|
|
|
await gu.sendKeys(Key.ESCAPE);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe(`in reference columns`, function() {
|
2024-05-29 21:55:21 +00:00
|
|
|
before(async () => {
|
|
|
|
const session = await gu.session().user('user1').login();
|
|
|
|
await session.loadDoc(`/doc/${docId}`);
|
|
|
|
});
|
|
|
|
|
2024-04-26 20:34:16 +00:00
|
|
|
it('creates dropdown conditions', async function() {
|
|
|
|
await gu.getCell(2, 1).click();
|
|
|
|
assert.isFalse(await driver.find('.test-field-dropdown-condition').isPresent());
|
|
|
|
await driver.find('.test-field-set-dropdown-condition').click();
|
2024-05-02 15:32:05 +00:00
|
|
|
await gu.waitAppFocus(false);
|
|
|
|
await gu.sendKeysSlowly(['choice']);
|
2024-04-26 20:34:16 +00:00
|
|
|
await gu.waitToPass(async () => {
|
|
|
|
const completions = await driver.findAll('.ace_autocomplete .ace_line', el => el.getText());
|
|
|
|
assert.deepEqual(completions, [
|
|
|
|
'choice\n ',
|
|
|
|
'choice\n.id\n ',
|
|
|
|
'choice\n.Name\n ',
|
|
|
|
'choice\n.Role\n ',
|
|
|
|
'choice\n.Supervisor\n '
|
|
|
|
]);
|
|
|
|
});
|
2024-05-07 21:52:51 +00:00
|
|
|
await gu.sendKeys('.Role == "Supervisor" and $Role != "Supervisor" and $id != 2', Key.ENTER);
|
2024-04-26 20:34:16 +00:00
|
|
|
await gu.waitForServer();
|
|
|
|
assert.equal(
|
|
|
|
await driver.find('.test-field-dropdown-condition .ace_line').getAttribute('textContent'),
|
2024-05-07 21:52:51 +00:00
|
|
|
'choice.Role == "Supervisor" and $Role != "Supervisor" and $id != 2\n'
|
2024-04-26 20:34:16 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
// Check that autocomplete values are filtered.
|
|
|
|
await gu.sendKeys(Key.ENTER);
|
|
|
|
assert.deepEqual(await driver.findAll('.test-autocomplete li', (el) => el.getText()), [
|
|
|
|
'Pavan Madilyn',
|
|
|
|
'Marie Ziyad',
|
|
|
|
]);
|
|
|
|
await gu.sendKeys(Key.ESCAPE);
|
2024-05-07 21:52:51 +00:00
|
|
|
|
|
|
|
// Should be no options on row 2 because of $id != 2 part of condition.
|
|
|
|
await gu.getCell(2, 2).click();
|
|
|
|
await gu.sendKeys(Key.ENTER);
|
|
|
|
assert.deepEqual(await driver.findAll('.test-autocomplete li', (el) => el.getText()), [
|
|
|
|
]);
|
|
|
|
await gu.sendKeys(Key.ESCAPE);
|
|
|
|
|
|
|
|
// Row 3 should be like row 1.
|
|
|
|
await gu.getCell(2, 3).click();
|
|
|
|
await gu.sendKeys(Key.ENTER);
|
|
|
|
assert.deepEqual(await driver.findAll('.test-autocomplete li', (el) => el.getText()), [
|
|
|
|
'Pavan Madilyn',
|
|
|
|
'Marie Ziyad',
|
|
|
|
]);
|
|
|
|
await gu.sendKeys(Key.ESCAPE);
|
|
|
|
|
2024-04-26 20:34:16 +00:00
|
|
|
await gu.getCell(2, 4).click();
|
|
|
|
await gu.sendKeys(Key.ENTER);
|
|
|
|
assert.isEmpty(await driver.findAll('.test-autocomplete li', (el) => el.getText()));
|
|
|
|
await gu.sendKeys(Key.ESCAPE);
|
|
|
|
await gu.getCell(2, 6).click();
|
|
|
|
await gu.sendKeys(Key.ENTER);
|
|
|
|
assert.deepEqual(await driver.findAll('.test-autocomplete li', (el) => el.getText()), [
|
|
|
|
'Marie Ziyad',
|
|
|
|
'Pavan Madilyn',
|
|
|
|
]);
|
|
|
|
await gu.sendKeys(Key.ESCAPE);
|
|
|
|
|
|
|
|
// Change the column type to Reference List and check values are still filtered.
|
|
|
|
await gu.setType('Reference List', {apply: true});
|
|
|
|
assert.equal(
|
|
|
|
await driver.find('.test-field-dropdown-condition .ace_line').getAttribute('textContent'),
|
2024-05-07 21:52:51 +00:00
|
|
|
'choice.Role == "Supervisor" and $Role != "Supervisor" and $id != 2\n'
|
2024-04-26 20:34:16 +00:00
|
|
|
);
|
|
|
|
await gu.getCell(2, 4).click();
|
|
|
|
await gu.sendKeys(Key.ENTER);
|
|
|
|
assert.isEmpty(await driver.findAll('.test-autocomplete li', (el) => el.getText()));
|
|
|
|
await gu.sendKeys(Key.ESCAPE);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('removes dropdown conditions', async function() {
|
|
|
|
await driver.find('.test-field-dropdown-condition').click();
|
|
|
|
await gu.sendKeys(await gu.selectAllKey(), Key.DELETE, Key.ENTER);
|
|
|
|
await gu.waitForServer();
|
|
|
|
|
|
|
|
// Check that autocomplete values are no longer filtered.
|
|
|
|
await gu.sendKeys(Key.ENTER);
|
|
|
|
assert.deepEqual(await driver.findAll('.test-autocomplete li', (el) => el.getText()), [
|
|
|
|
'Emma Thamir',
|
|
|
|
'Holger Klyment',
|
|
|
|
'Marie Ziyad',
|
|
|
|
'Olivier Bipin',
|
|
|
|
'Pavan Madilyn',
|
|
|
|
]);
|
|
|
|
await gu.sendKeys(Key.ESCAPE);
|
|
|
|
|
|
|
|
// Change the column type back to Reference and check values are still no longer filtered.
|
|
|
|
await gu.setType('Reference', {apply: true});
|
|
|
|
assert.isFalse(await driver.find('.test-field-dropdown-condition').isPresent());
|
|
|
|
await gu.sendKeys(Key.ENTER);
|
|
|
|
assert.deepEqual(await driver.findAll('.test-autocomplete li', (el) => el.getText()), [
|
|
|
|
'Emma Thamir',
|
|
|
|
'Holger Klyment',
|
|
|
|
'Marie Ziyad',
|
|
|
|
'Olivier Bipin',
|
|
|
|
'Pavan Madilyn',
|
|
|
|
]);
|
|
|
|
await gu.sendKeys(Key.ESCAPE);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('reports errors', async function() {
|
|
|
|
// Check syntax errors are reported, but not saved.
|
|
|
|
await driver.find('.test-field-set-dropdown-condition').click();
|
|
|
|
await gu.sendKeys('!@#$%^', Key.ENTER);
|
|
|
|
await gu.waitForServer();
|
|
|
|
assert.equal(
|
|
|
|
await driver.find('.test-field-dropdown-condition-error').getText(),
|
|
|
|
'SyntaxError invalid syntax on line 1 col 1'
|
|
|
|
);
|
|
|
|
await gu.reloadDoc();
|
|
|
|
assert.isFalse(await driver.find('.test-field-dropdown-condition-error').isPresent());
|
|
|
|
|
|
|
|
// Check compilation errors are reported and saved.
|
|
|
|
await driver.find('.test-field-set-dropdown-condition').click();
|
|
|
|
await gu.sendKeys('foo', Key.ENTER);
|
|
|
|
await gu.waitForServer();
|
|
|
|
assert.equal(
|
|
|
|
await driver.find('.test-field-dropdown-condition-error').getText(),
|
|
|
|
"Unknown variable 'foo'"
|
|
|
|
);
|
|
|
|
await gu.reloadDoc();
|
|
|
|
assert.equal(
|
|
|
|
await driver.find('.test-field-dropdown-condition-error').getText(),
|
|
|
|
"Unknown variable 'foo'"
|
|
|
|
);
|
|
|
|
|
|
|
|
// Check that the autocomplete dropdown also reports an error.
|
|
|
|
await gu.sendKeys(Key.ENTER);
|
|
|
|
assert.equal(
|
|
|
|
await driver.find('.test-autocomplete-no-items-message').getText(),
|
|
|
|
'Error in dropdown condition'
|
|
|
|
);
|
|
|
|
await gu.sendKeys(Key.ESCAPE);
|
|
|
|
|
|
|
|
// Check evaluation errors are also reported in the dropdown.
|
|
|
|
await driver.find('.test-field-dropdown-condition').click();
|
|
|
|
await gu.sendKeys(await gu.selectAllKey(), Key.DELETE, '[] not in 5', Key.ENTER);
|
|
|
|
await gu.waitForServer();
|
|
|
|
await gu.sendKeys(Key.ENTER);
|
|
|
|
assert.equal(
|
|
|
|
await driver.find('.test-autocomplete-no-items-message').getText(),
|
|
|
|
'Error in dropdown condition'
|
|
|
|
);
|
|
|
|
await gu.sendKeys(Key.ESCAPE);
|
|
|
|
});
|
|
|
|
});
|
2024-05-29 21:55:21 +00:00
|
|
|
|
|
|
|
it('supports user variable', async function() {
|
|
|
|
// Filter dropdown values based on a user attribute.
|
|
|
|
await gu.getCell(1, 1).click();
|
|
|
|
await driver.find('.test-field-set-dropdown-condition').click();
|
|
|
|
await gu.waitAppFocus(false);
|
|
|
|
await gu.sendKeysSlowly(['user.']);
|
|
|
|
await gu.waitToPass(async () => {
|
|
|
|
const completions = await driver.findAll('.ace_autocomplete .ace_line', el => el.getText());
|
|
|
|
assert.deepEqual(completions, [
|
|
|
|
'user.\nAccess\n ',
|
|
|
|
'user.\nEmail\n ',
|
|
|
|
'user.\nIsLoggedIn\n ',
|
|
|
|
'user.\nLinkKey.\n ',
|
|
|
|
'user.\nName\n ',
|
|
|
|
'user.\nOrigin\n ',
|
|
|
|
'user.\nRoles.Admin\n ',
|
|
|
|
'user.\nRoles.Email\n ',
|
|
|
|
''
|
|
|
|
]);
|
|
|
|
});
|
|
|
|
await gu.sendKeys('Roles.Admin == True', Key.ENTER);
|
|
|
|
await gu.waitForServer();
|
|
|
|
|
|
|
|
// Check that user1 (who is an admin) can see dropdown values.
|
|
|
|
await gu.sendKeys(Key.ENTER);
|
|
|
|
assert.deepEqual(await driver.findAll('.test-autocomplete li', (el) => el.getText()), [
|
|
|
|
'Trainee',
|
|
|
|
'Supervisor',
|
|
|
|
]);
|
|
|
|
await gu.sendKeys(Key.ESCAPE);
|
|
|
|
|
|
|
|
// Switch to user2 (who is not an admin), and check that they can't see any dropdown values.
|
|
|
|
const session = await gu.session().user('user2').login();
|
|
|
|
await session.loadDoc(`/doc/${docId}`);
|
|
|
|
await gu.getCell(1, 1).click();
|
|
|
|
await gu.sendKeys(Key.ENTER);
|
|
|
|
assert.deepEqual(await driver.findAll('.test-autocomplete li', (el) => el.getText()), []);
|
|
|
|
await gu.sendKeys(Key.ESCAPE);
|
|
|
|
});
|
2024-04-26 20:34:16 +00:00
|
|
|
});
|