From 61f954ff05ae183154522664a1c3d9421591a792 Mon Sep 17 00:00:00 2001 From: Paul Fitzpatrick Date: Mon, 31 Jul 2023 21:10:59 +0100 Subject: [PATCH] move getTemplateOrg method; enable template org in docker tests (#602) * move getTemplateOrg method; enable template org in docker tests This moves the `getTemplateOrg` method to a neutral venue for the convenience of `grist-static`, otherwise a lot of awkward dependencies get pulled in needlessly in new parts of the app. This also fixes docker tests using the template org. --- app/gen-server/ApiServer.ts | 2 +- app/server/lib/ActiveDoc.ts | 2 +- app/server/lib/AppEndpoint.ts | 3 ++- app/server/lib/gristSettings.ts | 13 ++++++++++++ app/server/lib/sendAppPage.ts | 14 +------------ test/nbrowser/CellColor.ts | 1 + test/nbrowser/SelectByRefList.ts | 2 +- test/nbrowser/SelectBySummary.ts | 36 +++++++++++++++++++------------- test/nbrowser/gristUtils.ts | 8 +++++++ test/nbrowser/homeUtil.ts | 7 ++++++- test/test_under_docker.sh | 1 + 11 files changed, 57 insertions(+), 32 deletions(-) create mode 100644 app/server/lib/gristSettings.ts diff --git a/app/gen-server/ApiServer.ts b/app/gen-server/ApiServer.ts index 542f2bf3..93738253 100644 --- a/app/gen-server/ApiServer.ts +++ b/app/gen-server/ApiServer.ts @@ -11,10 +11,10 @@ import {getAuthorizedUserId, getUserId, getUserProfiles, RequestWithLogin} from import {getSessionUser, linkOrgWithEmail} from 'app/server/lib/BrowserSession'; import {expressWrap} from 'app/server/lib/expressWrap'; import {RequestWithOrg} from 'app/server/lib/extractOrg'; +import {getTemplateOrg} from 'app/server/lib/gristSettings'; import log from 'app/server/lib/log'; import {addPermit, clearSessionCacheIfNeeded, getDocScope, getScope, integerParam, isParameterOn, optStringParam, sendOkReply, sendReply, stringParam} from 'app/server/lib/requestUtils'; -import {getTemplateOrg} from 'app/server/lib/sendAppPage'; import {IWidgetRepository} from 'app/server/lib/WidgetRepository'; import {User} from './entity/User'; diff --git a/app/server/lib/ActiveDoc.ts b/app/server/lib/ActiveDoc.ts index 9d30976e..34e7f53c 100644 --- a/app/server/lib/ActiveDoc.ts +++ b/app/server/lib/ActiveDoc.ts @@ -89,6 +89,7 @@ import {Authorizer} from 'app/server/lib/Authorizer'; import {checksumFile} from 'app/server/lib/checksumFile'; import {Client} from 'app/server/lib/Client'; import {DEFAULT_CACHE_TTL, DocManager} from 'app/server/lib/DocManager'; +import {getTemplateOrg} from 'app/server/lib/gristSettings'; import {ICreateActiveDocOptions} from 'app/server/lib/ICreate'; import {makeForkIds} from 'app/server/lib/idUtils'; import {GRIST_DOC_SQL, GRIST_DOC_WITH_TABLE1_SQL} from 'app/server/lib/initialDocSql'; @@ -97,7 +98,6 @@ import log from 'app/server/lib/log'; import {LogMethods} from "app/server/lib/LogMethods"; import {NullSandbox, UnavailableSandboxMethodError} from 'app/server/lib/NullSandbox'; import {DocRequests} from 'app/server/lib/Requests'; -import {getTemplateOrg} from 'app/server/lib/sendAppPage'; import {shortDesc} from 'app/server/lib/shortDesc'; import {TableMetadataLoader} from 'app/server/lib/TableMetadataLoader'; import {DocTriggers} from "app/server/lib/Triggers"; diff --git a/app/server/lib/AppEndpoint.ts b/app/server/lib/AppEndpoint.ts index a29ed2b8..41968271 100644 --- a/app/server/lib/AppEndpoint.ts +++ b/app/server/lib/AppEndpoint.ts @@ -20,10 +20,11 @@ import {DocStatus, IDocWorkerMap} from 'app/server/lib/DocWorkerMap'; import {expressWrap} from 'app/server/lib/expressWrap'; import {DocTemplate, GristServer} from 'app/server/lib/GristServer'; import {getCookieDomain} from 'app/server/lib/gristSessions'; +import {getTemplateOrg} from 'app/server/lib/gristSettings'; import {getAssignmentId} from 'app/server/lib/idUtils'; import log from 'app/server/lib/log'; import {adaptServerUrl, addOrgToPathIfNeeded, pruneAPIResult, trustOrigin} from 'app/server/lib/requestUtils'; -import {getTemplateOrg, ISendAppPageOptions} from 'app/server/lib/sendAppPage'; +import {ISendAppPageOptions} from 'app/server/lib/sendAppPage'; export interface AttachOptions { app: express.Application; // Express app to which to add endpoints diff --git a/app/server/lib/gristSettings.ts b/app/server/lib/gristSettings.ts new file mode 100644 index 00000000..3ffb8197 --- /dev/null +++ b/app/server/lib/gristSettings.ts @@ -0,0 +1,13 @@ +import {appSettings} from 'app/server/lib/AppSettings'; + +export function getTemplateOrg() { + let org = appSettings.section('templates').flag('org').readString({ + envVar: 'GRIST_TEMPLATE_ORG', + }); + if (!org) { return null; } + + if (process.env.GRIST_ID_PREFIX) { + org += `-${process.env.GRIST_ID_PREFIX}`; + } + return org; +} diff --git a/app/server/lib/sendAppPage.ts b/app/server/lib/sendAppPage.ts index 19336982..8aaf48be 100644 --- a/app/server/lib/sendAppPage.ts +++ b/app/server/lib/sendAppPage.ts @@ -3,10 +3,10 @@ import {isAffirmative} from 'app/common/gutil'; import {getTagManagerSnippet} from 'app/common/tagManager'; import {Document} from 'app/common/UserAPI'; import {SUPPORT_EMAIL} from 'app/gen-server/lib/HomeDBManager'; -import {appSettings} from 'app/server/lib/AppSettings'; import {isAnonymousUser, isSingleUserMode, RequestWithLogin} from 'app/server/lib/Authorizer'; import {RequestWithOrg} from 'app/server/lib/extractOrg'; import {GristServer} from 'app/server/lib/GristServer'; +import {getTemplateOrg} from 'app/server/lib/gristSettings'; import {getSupportedEngineChoices} from 'app/server/lib/serverUtils'; import {readLoadedLngs, readLoadedNamespaces} from 'app/server/localization'; import * as express from 'express'; @@ -154,18 +154,6 @@ export function makeSendAppPage(opts: { }; } -export function getTemplateOrg() { - let org = appSettings.section('templates').flag('org').readString({ - envVar: 'GRIST_TEMPLATE_ORG', - }); - if (!org) { return null; } - - if (process.env.GRIST_ID_PREFIX) { - org += `-${process.env.GRIST_ID_PREFIX}`; - } - return org; -} - function shouldSupportAnon() { // Enable UI for anonymous access if a flag is explicitly set in the environment return process.env.GRIST_SUPPORT_ANON === "true"; diff --git a/test/nbrowser/CellColor.ts b/test/nbrowser/CellColor.ts index 3df31e6c..00f48802 100644 --- a/test/nbrowser/CellColor.ts +++ b/test/nbrowser/CellColor.ts @@ -306,6 +306,7 @@ describe('CellColor', function() { // Empty cell to clear error from converting toggle to date await cell.click(); await driver.sendKeys(Key.DELETE); + await gu.waitAppFocus(true); const clip = cell.find('.field_clip'); diff --git a/test/nbrowser/SelectByRefList.ts b/test/nbrowser/SelectByRefList.ts index 9c96d5a4..6d3d3b56 100644 --- a/test/nbrowser/SelectByRefList.ts +++ b/test/nbrowser/SelectByRefList.ts @@ -232,7 +232,7 @@ async function checkSelectingRecords(selectBy: string, sourceData: string[][], n for (let rowNum = 1; rowNum <= 3; rowNum++) { // Click an anchor link const anchorCell = gu.getCell({section: "Anchors", rowNum, col: 1}); - await anchorCell.find('.test-tb-link').click(); + await driver.withActions(a => a.click(anchorCell.find('.test-tb-link'))); // Check that navigation to the link target worked assert.equal(await gu.getActiveSectionTitle(), "LINKTARGET"); diff --git a/test/nbrowser/SelectBySummary.ts b/test/nbrowser/SelectBySummary.ts index 8b7cbdea..30f81415 100644 --- a/test/nbrowser/SelectBySummary.ts +++ b/test/nbrowser/SelectBySummary.ts @@ -1,25 +1,26 @@ import * as _ from 'lodash'; -import {addToRepl, assert, driver} from 'mocha-webdriver'; +import {assert, driver} from 'mocha-webdriver'; import {enterRulePart, findDefaultRuleSet} from 'test/nbrowser/aclTestUtils'; import * as gu from 'test/nbrowser/gristUtils'; -import {server, setupTestSuite} from 'test/nbrowser/testUtils'; +import {setupTestSuite} from 'test/nbrowser/testUtils'; describe('SelectBySummary', function() { this.timeout(50000); - setupTestSuite(); - addToRepl('gu2', gu); + const cleanup = setupTestSuite(); + let headers: Record; gu.bigScreen(); before(async function() { - await server.simulateLogin("Chimpy", "chimpy@getgrist.com", 'nasa'); - const doc = await gu.importFixturesDoc('chimpy', 'nasa', 'Horizon', - 'SelectBySummary.grist', false); - await driver.get(`${server.getHost()}/o/nasa/doc/${doc.id}`); - await gu.waitForDocToLoad(); + const session = await gu.session().teamSite.login(); + await session.tempDoc(cleanup, 'SelectBySummary.grist'); + headers = { + Authorization: `Bearer ${session.getApiKey()}` + }; }); - it('should filter a source table selected by a summary table', async function() { + it('should filter a source table selected by a summary table (first option)', async function() { await checkSelectingRecords( + headers, ['onetwo'], [ '1', '16', @@ -40,8 +41,11 @@ describe('SelectBySummary', function() { ], ], ); + }); + it('should filter a source table selected by a summary table (second option)', async function() { await checkSelectingRecords( + headers, ['choices'], [ 'a', '14', @@ -67,9 +71,11 @@ describe('SelectBySummary', function() { ], ], ); + }); - + it('should filter a source table selected by a summary table (both options)', async function() { await checkSelectingRecords( + headers, ['onetwo', 'choices'], [ '1', 'a', '6', @@ -104,7 +110,6 @@ describe('SelectBySummary', function() { ], ], ); - }); it('should create new rows in the source table (link target) with correct default values', @@ -153,6 +158,7 @@ describe('SelectBySummary', function() { // selecting by the two less detailed summaries. // There was a bug previously that this would not work while the summary source table (Table1) was hidden. await checkSelectingRecords( + headers, ['onetwo'], [ '1', '16', @@ -175,6 +181,7 @@ describe('SelectBySummary', function() { ); await checkSelectingRecords( + headers, ['choices'], [ 'a', '14', @@ -208,6 +215,7 @@ describe('SelectBySummary', function() { * to the corresponding subarray of `targetData`. */ async function checkSelectingRecords( + headers: Record, groubyColumns: string[], summaryData: string[], targetData: string[][], @@ -243,7 +251,7 @@ async function checkSelectingRecords( ); if (targetSection === 'TABLE1') { assert.equal(await countCell.getText(), numTargetRows.toString()); - const csvCells = await gu.downloadSectionCsvGridCells(targetSection); + const csvCells = await gu.downloadSectionCsvGridCells(targetSection, headers); // visible cells text uses newlines to separate list items, CSV export uses commas const expectedCsvCells = targetGroup.map(s => s.replace("\n", ", ")); assert.deepEqual(csvCells, expectedCsvCells); @@ -259,7 +267,7 @@ async function checkSelectingRecords( for (let rowNum = 1; rowNum <= 8; rowNum++) { // Click an anchor link const anchorCell = gu.getCell({section: "Anchors", rowNum, col: 1}); - await anchorCell.find('.test-tb-link').click(); + await driver.withActions(a => a.click(anchorCell.find('.test-tb-link'))); // Check that navigation to the link target worked assert.equal(await gu.getActiveSectionTitle(), "TABLE1"); diff --git a/test/nbrowser/gristUtils.ts b/test/nbrowser/gristUtils.ts index 4535c19f..f4b81e3e 100644 --- a/test/nbrowser/gristUtils.ts +++ b/test/nbrowser/gristUtils.ts @@ -61,6 +61,7 @@ export const uploadFixtureDoc = homeUtil.uploadFixtureDoc.bind(homeUtil); export const getWorkspaceId = homeUtil.getWorkspaceId.bind(homeUtil); export const listDocs = homeUtil.listDocs.bind(homeUtil); export const createHomeApi = homeUtil.createHomeApi.bind(homeUtil); +export const getApiKey = homeUtil.getApiKey.bind(homeUtil); export const simulateLogin = homeUtil.simulateLogin.bind(homeUtil); export const removeLogin = homeUtil.removeLogin.bind(homeUtil); export const enableTips = homeUtil.enableTips.bind(homeUtil); @@ -2047,6 +2048,13 @@ export class Session { return createHomeApi(this.settings.name, this.settings.orgDomain, this.settings.email); } + public getApiKey(): string|null { + if (this.settings.email === 'anon@getgrist.com') { + return getApiKey(null); + } + return getApiKey(this.settings.name, this.settings.email); + } + // Get the id of this user. public async getUserId(): Promise { await this.login(); diff --git a/test/nbrowser/homeUtil.ts b/test/nbrowser/homeUtil.ts index e90826ad..6dea6c49 100644 --- a/test/nbrowser/homeUtil.ts +++ b/test/nbrowser/homeUtil.ts @@ -316,9 +316,14 @@ export class HomeUtil { // A helper to create a UserAPI instance for a given useranme and org, that targets the home server // Username can be null for anonymous access. public createHomeApi(username: string|null, org: string, email?: string): UserAPIImpl { + const apiKey = this.getApiKey(username, email); + return this._createHomeApiUsingApiKey(apiKey, org); + } + + public getApiKey(username: string|null, email?: string): string | null { const name = (username || '').toLowerCase(); const apiKey = username && ((email && this._apiKey.get(email)) || `api_key_for_${name}`); - return this._createHomeApiUsingApiKey(apiKey, org); + return apiKey; } /** diff --git a/test/test_under_docker.sh b/test/test_under_docker.sh index ba7af76b..e5d573ba 100755 --- a/test/test_under_docker.sh +++ b/test/test_under_docker.sh @@ -41,6 +41,7 @@ docker run --name $DOCKER_CONTAINER --rm \ --env GRIST_LOG_LEVEL=$GRIST_LOG_LEVEL \ --env GRIST_LOG_SKIP_HTTP=${DEBUG:-false} \ --env TEST_SUPPORT_API_KEY=api_key_for_support \ + --env GRIST_TEMPLATE_ORG=templates \ ${TEST_IMAGE:-gristlabs/grist} & DOCKER_PID="$!"