(core) Try to get Billing tests to pass consistently.

Summary:
1. Set pageLoad timeout to 10s (default is 5 minutes)
2. Disable chrome's prompts to save credit card info, which may be
   affecting Stripe pages
3. Periodically record of logs and screenshots for the most-failing test case
   so that whenever it fails in a bad way (timeout with no indication of
   what's wrong), we can hope to find out what's wrong.

Test Plan: Planning to celebrate if Billing tests pass.

Reviewers: georgegevoian

Reviewed By: georgegevoian

Subscribers: georgegevoian

Differential Revision: https://phab.getgrist.com/D4193
This commit is contained in:
Dmitry S 2024-03-13 12:27:09 -04:00
parent 17857ec1f0
commit e4d104ee41

View File

@ -16,9 +16,12 @@
* first-failure for debugging and quick reruns. * first-failure for debugging and quick reruns.
*/ */
import log from 'app/server/lib/log'; import log from 'app/server/lib/log';
import {addToRepl, assert, driver, enableDebugCapture, Key, setOptionsModifyFunc, useServer} from 'mocha-webdriver'; import {addToRepl, assert, driver, enableDebugCapture, ITimeouts,
Key, setOptionsModifyFunc, useServer} from 'mocha-webdriver';
import * as gu from 'test/nbrowser/gristUtils'; import * as gu from 'test/nbrowser/gristUtils';
import {server} from 'test/nbrowser/testServer'; import {server} from 'test/nbrowser/testServer';
import * as path from 'path';
import * as fs from 'fs/promises';
// Exports the server object with useful methods such as getHost(), waitServerReady(), // Exports the server object with useful methods such as getHost(), waitServerReady(),
// simulateLogin(), etc. // simulateLogin(), etc.
@ -72,6 +75,10 @@ setOptionsModifyFunc(({chromeOpts, firefoxOpts}) => {
}), }),
"download.default_directory": server.testDir, "download.default_directory": server.testDir,
"savefile.default_directory": server.testDir, "savefile.default_directory": server.testDir,
"autofill": {
profile_enabled: false,
credit_card_enabled: false,
},
}); });
}); });
@ -82,6 +89,10 @@ interface TestSuiteOptions {
// If set, clear user preferences for all test users at the end of the suite. It should be used // If set, clear user preferences for all test users at the end of the suite. It should be used
// for suites that modify preferences. Not that it only works in dev, not in deployment tests. // for suites that modify preferences. Not that it only works in dev, not in deployment tests.
clearUserPrefs?: boolean; clearUserPrefs?: boolean;
// Max milliseconds to wait for a page to finish loading. E.g. affects clicks that cause
// navigation, which wait for that. A navigation that takes longer will throw an exception.
pageLoadTimeout?: number;
} }
// Sets up the test suite to use the Grist server, and also to record logs and screenshots after // Sets up the test suite to use the Grist server, and also to record logs and screenshots after
@ -122,6 +133,10 @@ export function setupTestSuite(options?: TestSuiteOptions) {
// with tests that don't use the same server. // with tests that don't use the same server.
after(async () => server.closeDatabase()); after(async () => server.closeDatabase());
if (options?.pageLoadTimeout) {
setDriverTimeoutsForSuite({pageLoad: options.pageLoadTimeout});
}
return setupRequirement({team: true, ...options}); return setupRequirement({team: true, ...options});
} }
@ -175,6 +190,21 @@ async function clearTestUserPreferences() {
await dbManager.testClearUserPrefs(emails); await dbManager.testClearUserPrefs(emails);
} }
export function setDriverTimeoutsForSuite(newTimeouts: ITimeouts) {
let prevTimeouts: ITimeouts|null = null;
before(async () => {
prevTimeouts = await driver.manage().getTimeouts();
await driver.manage().setTimeouts(newTimeouts);
});
after(async () => {
if (prevTimeouts) {
await driver.manage().setTimeouts(prevTimeouts);
}
});
}
export type CleanupFunc = (() => void|Promise<void>); export type CleanupFunc = (() => void|Promise<void>);
/** /**
@ -287,3 +317,39 @@ export function setupRequirement(options: TestSuiteOptions) {
}); });
return cleanup; return cleanup;
} }
export async function withDriverLogging(
test: Mocha.Runnable|undefined, periodMs: number, timeoutMs: number,
callback: () => Promise<void>
) {
const dir = process.env.MOCHA_WEBDRIVER_LOGDIR!;
assert.isOk(dir, "driverLogging: MOCHA_WEBDRIVER_LOGDIR not set");
const testName = test?.file ? path.basename(test.file, path.extname(test.file)) : "unnamed";
const logPath = path.resolve(dir, `${testName}-driverLogging.log`);
await fs.mkdir(dir, {recursive: true});
let running = false;
async function repeat() {
if (running) {
console.log("driverLogging: skipping because previous repeat still running");
return;
}
running = true;
try {
await driver.saveScreenshot(`${testName}-driverLoggingScreenshot-{N}.png`);
const messages = await driver.fetchLogs('driver');
await fs.appendFile(logPath, messages.join("\n") + "\n");
} finally {
running = false;
}
}
const periodic = setInterval(repeat, periodMs);
const timeout = setTimeout(() => clearInterval(periodic), timeoutMs);
try {
return await callback();
} finally {
clearInterval(periodic);
clearTimeout(timeout);
}
}