gristlabs_grist-core/test/nbrowser/SupportGrist.ts
Dmitry S e380fcfa90 (core) Admin Panel and InstallAdmin class to identify installation admins.
Summary:
- Add InstallAdmin class to identify users who can manage Grist installation.

  This is overridable by different Grist flavors (e.g. different in SaaS).
  It generalizes previous logic used to decide who can control Activation
  settings (e.g. enable telemetry).

- Implement a basic Admin Panel at /admin, and move items previously in the
  "Support Grist" page into the "Support Grist" section of the Admin Panel.

- Replace "Support Grist" menu items with "Admin Panel" and show only to admins.

- Add "Support Grist" links to Github sponsorship to user-account menu.

- Add "Support Grist" button to top-bar, which
  - for admins, replaces the previous "Contribute" button and reopens the "Support Grist / opt-in to telemetry" nudge (unchanged)
  - for everyone else, links to Github sponsorship
  - in either case, user can dismiss it.

Test Plan: Shuffled some test cases between Support Grist and the new Admin Panel, and added some new cases.

Reviewers: jarek, paulfitz

Reviewed By: jarek, paulfitz

Differential Revision: https://phab.getgrist.com/D4194
2024-03-25 12:18:38 -04:00

270 lines
10 KiB
TypeScript

import {GristLoadConfig} from 'app/common/gristUrls';
import {TelemetryLevel} from 'app/common/Telemetry';
import {assert, driver} from 'mocha-webdriver';
import * as gu from 'test/nbrowser/gristUtils';
import {server, setupTestSuite} from 'test/nbrowser/testUtils';
import * as testUtils from 'test/server/testUtils';
const sponsorshipUrl = 'https://github.com/sponsors/gristlabs';
describe('SupportGrist', function() {
this.timeout(30000);
setupTestSuite();
let oldEnv: testUtils.EnvironmentSnapshot;
let session: gu.Session;
afterEach(() => gu.checkForErrors());
after(async function() {
await server.restart();
});
describe('in grist-core', function() {
before(async function() {
oldEnv = new testUtils.EnvironmentSnapshot();
process.env.GRIST_TEST_SERVER_DEPLOYMENT_TYPE = 'core';
process.env.GRIST_DEFAULT_EMAIL = gu.session().email;
await server.restart();
});
after(async function() {
oldEnv.restore();
});
describe('when user is not a manager', function() {
before(async function() {
session = await gu.session().user('user2').personalSite.login();
await session.loadDocMenu('/');
});
it('does not show a nudge on the doc menu', async function() {
await assertNudgeCardShown(false);
await assertSupportButtonShown(true, {isSponsorLink: true});
});
it('shows a link to the Support Grist page in the user menu', async function() {
await gu.openAccountMenu();
await assertMenuHasAdminPanel(false);
await assertMenuHasSupportGrist(true);
});
});
describe('when user is a manager', function() {
before(async function() {
session = await gu.session().personalSite.login();
await session.loadDocMenu('/');
});
it('shows a nudge on the doc menu', async function() {
// Check that the nudge is expanded by default.
await assertSupportButtonShown(false);
await assertNudgeCardShown(true);
// Reload the doc menu and check that it's still expanded.
await session.loadDocMenu('/');
await assertSupportButtonShown(false);
await assertNudgeCardShown(true);
// Close the nudge and check that it's now collapsed.
await driver.find('.test-support-nudge-close').click();
await assertSupportButtonShown(true, {isSponsorLink: false});
await assertNudgeCardShown(false);
// Reload again, and check that it's still collapsed.
await session.loadDocMenu('/');
await assertSupportButtonShown(true, {isSponsorLink: false});
await assertNudgeCardShown(false);
// Dismiss the contribute button and check that it's now gone, even after reloading.
await driver.find('.test-support-grist-button').mouseMove();
await driver.find('.test-support-grist-button-dismiss').click();
await assertSupportButtonShown(false);
await assertNudgeCardShown(false);
await session.loadDocMenu('/');
await assertSupportButtonShown(false);
await assertNudgeCardShown(false);
});
it('shows a link to Admin Panel and Support Grist in the user menu', async function() {
await gu.openAccountMenu();
await assertMenuHasAdminPanel(true);
await assertMenuHasSupportGrist(true);
});
it('supports opting in to telemetry from the nudge', async function() {
// Reset all dismissed popups, including the telemetry nudge.
await driver.executeScript('resetDismissedPopups();');
await gu.waitForServer();
await session.loadDocMenu('/');
// Opt in to telemetry and reload the page.
await driver.find('.test-support-nudge-opt-in').click();
await driver.findWait('.test-support-nudge-close-button', 1000).click();
await assertSupportButtonShown(false);
await assertNudgeCardShown(false);
await session.loadDocMenu('/');
// Check that the nudge is no longer shown and telemetry is set to "limited".
await assertSupportButtonShown(false);
await assertNudgeCardShown(false);
await assertTelemetryLevel('limited');
});
it('does not show the nudge if telemetry is enabled', async function() {
// Reset all dismissed popups, including the telemetry nudge.
await driver.executeScript('resetDismissedPopups();');
await gu.waitForServer();
// Reload the doc menu and check that the nudge still isn't shown.
await session.loadDocMenu('/');
await assertNudgeCardShown(false);
// We still show the "Support Grist" button linking to sponsorship page.
await assertSupportButtonShown(true, {isSponsorLink: true});
// Disable telemetry from the Support Grist page.
await gu.openAccountMenu();
await driver.find('.test-usermenu-admin-panel').click();
await driver.findWait('.test-admin-panel', 2000);
await driver.find('.test-admin-panel-item-name-telemetry').click();
await driver.sleep(500); // Wait for section to expand.
await driver.findContentWait(
'.test-support-grist-page-telemetry-section button', /Opt out of Telemetry/, 2000).click();
await driver.findContentWait('.test-support-grist-page-telemetry-section button', /Opt in to Telemetry/, 2000);
// Reload the doc menu and check that the nudge is now shown.
await gu.loadDocMenu('/');
await assertSupportButtonShown(false);
await assertNudgeCardShown(true);
});
it('shows sponsorship link when no telemetry nudge, and allows dismissing it', async function() {
// Reset all dismissed popups, including the telemetry nudge.
await driver.executeScript('resetDismissedPopups();');
await gu.waitForServer();
// Opt in to telemetry
const api = session.createHomeApi();
await api.testRequest(`${api.getBaseUrl()}/api/install/prefs`, {
method: 'patch',
body: JSON.stringify({telemetry: {telemetryLevel: 'limited'}}),
});
await session.loadDocMenu('/');
await assertTelemetryLevel('limited');
// We still show the "Support Grist" button linking to sponsorship page.
await assertSupportButtonShown(true, {isSponsorLink: true});
await assertNudgeCardShown(false);
// we can dismiss it.
await driver.find('.test-support-grist-button').mouseMove();
await driver.find('.test-support-grist-button-dismiss').click();
await assertSupportButtonShown(false);
// And this will get remembered.
await session.loadDocMenu('/');
await assertNudgeCardShown(false);
await assertSupportButtonShown(false);
});
});
});
describe('in grist-saas', function() {
before(async function() {
oldEnv = new testUtils.EnvironmentSnapshot();
process.env.GRIST_TEST_SERVER_DEPLOYMENT_TYPE = 'saas';
process.env.GRIST_DEFAULT_EMAIL = gu.session().email;
await server.restart();
session = await gu.session().personalSite.login();
await session.loadDocMenu('/');
});
after(async function() {
oldEnv.restore();
});
it('does not show a nudge on the doc menu', async function() {
await assertSupportButtonShown(false);
await assertNudgeCardShown(false);
});
it('shows Admin Panel but not Support Grist in the user menu for admin', async function() {
await gu.openAccountMenu();
await assertMenuHasAdminPanel(true);
await assertMenuHasSupportGrist(false);
});
it('does not show Admin Panel or Support Grist in the user menu for non-admin', async function() {
session = await gu.session().user('user2').personalSite.login();
await session.loadDocMenu('/');
await gu.openAccountMenu();
await assertMenuHasAdminPanel(false);
await assertMenuHasSupportGrist(false);
});
});
describe('in grist-enterprise', function() {
before(async function() {
oldEnv = new testUtils.EnvironmentSnapshot();
process.env.GRIST_TEST_SERVER_DEPLOYMENT_TYPE = 'enterprise';
process.env.GRIST_DEFAULT_EMAIL = gu.session().email;
await server.restart();
session = await gu.session().personalSite.login();
await session.loadDocMenu('/');
});
after(async function() {
oldEnv.restore();
});
it('does not show a nudge on the doc menu', async function() {
await assertSupportButtonShown(false);
await assertNudgeCardShown(false);
});
it('shows Admin Panel but not Support Grist page in the user menu', async function() {
await gu.openAccountMenu();
await assertMenuHasAdminPanel(true);
await assertMenuHasSupportGrist(false);
});
});
});
async function assertSupportButtonShown(isShown: false): Promise<void>;
async function assertSupportButtonShown(isShown: true, opts: {isSponsorLink: boolean}): Promise<void>;
async function assertSupportButtonShown(isShown: boolean, opts?: {isSponsorLink: boolean}) {
const button = driver.find('.test-support-grist-button');
assert.equal(await button.isPresent() && await button.isDisplayed(), isShown);
if (isShown) {
assert.equal(await button.getAttribute('href'), opts?.isSponsorLink ? sponsorshipUrl : null);
}
}
async function assertNudgeCardShown(isShown: boolean) {
const card = driver.find('.test-support-nudge');
assert.equal(await card.isPresent() && await card.isDisplayed(), isShown);
}
async function assertMenuHasAdminPanel(isShown: boolean) {
const elem = driver.find('.test-usermenu-admin-panel');
assert.equal(await elem.isPresent() && await elem.isDisplayed(), isShown);
if (isShown) {
assert.match(await elem.getAttribute('href'), /.*\/admin$/);
}
}
async function assertMenuHasSupportGrist(isShown: boolean) {
const elem = driver.find('.test-usermenu-support-grist');
assert.equal(await elem.isPresent() && await elem.isDisplayed(), isShown);
if (isShown) {
assert.equal(await elem.getAttribute('href'), sponsorshipUrl);
}
}
async function assertTelemetryLevel(level: TelemetryLevel) {
const {telemetry}: GristLoadConfig = await driver.executeScript('return window.gristConfig');
assert.equal(telemetry?.telemetryLevel, level);
}