2023-07-18 07:24:10 +00:00
|
|
|
import {DocCreationInfo} from 'app/common/DocListAPI';
|
|
|
|
import {DocAPI} from 'app/common/UserAPI';
|
|
|
|
import {assert, driver, Key} from 'mocha-webdriver';
|
|
|
|
import * as gu from 'test/nbrowser/gristUtils';
|
|
|
|
import {server, setupTestSuite} from 'test/nbrowser/testUtils';
|
|
|
|
import {EnvironmentSnapshot} from 'test/server/testUtils';
|
|
|
|
import {WebhookFields} from "../../app/common/Triggers";
|
|
|
|
|
|
|
|
describe('WebhookOverflow', function () {
|
|
|
|
this.timeout(30000);
|
|
|
|
const cleanup = setupTestSuite();
|
|
|
|
let session: gu.Session;
|
|
|
|
let oldEnv: EnvironmentSnapshot;
|
|
|
|
let doc: DocCreationInfo;
|
|
|
|
let docApi: DocAPI;
|
2023-10-31 13:07:02 +00:00
|
|
|
gu.bigScreen();
|
2023-07-18 07:24:10 +00:00
|
|
|
|
|
|
|
before(async function () {
|
|
|
|
oldEnv = new EnvironmentSnapshot();
|
|
|
|
process.env.ALLOWED_WEBHOOK_DOMAINS = '*';
|
2023-10-31 13:07:02 +00:00
|
|
|
process.env.GRIST_MAX_QUEUE_SIZE = '4';
|
2023-07-18 07:24:10 +00:00
|
|
|
await server.restart();
|
|
|
|
session = await gu.session().teamSite.login();
|
|
|
|
const api = session.createHomeApi();
|
|
|
|
doc = await session.tempDoc(cleanup, 'Hello.grist');
|
|
|
|
docApi = api.getDocAPI(doc.id);
|
|
|
|
await api.applyUserActions(doc.id, [
|
|
|
|
['AddTable', 'Table2', [{id: 'A'}, {id: 'B'}, {id: 'C'}, {id: 'D'}, {id: 'E'}]],
|
2023-10-31 13:07:02 +00:00
|
|
|
['AddRecord', 'Table2', null, {}],
|
2023-07-18 07:24:10 +00:00
|
|
|
]);
|
|
|
|
const webhookDetails: WebhookFields = {
|
|
|
|
url: 'https://localhost/WrongWebhook',
|
2023-10-31 13:07:02 +00:00
|
|
|
eventTypes: ["update"],
|
2023-07-18 07:24:10 +00:00
|
|
|
enabled: true,
|
|
|
|
name: 'test webhook',
|
|
|
|
tableId: 'Table2',
|
2024-04-12 20:04:37 +00:00
|
|
|
watchedColIds: []
|
2023-07-18 07:24:10 +00:00
|
|
|
};
|
|
|
|
await docApi.addWebhook(webhookDetails);
|
2023-10-31 13:07:02 +00:00
|
|
|
await docApi.addWebhook(webhookDetails);
|
2023-07-18 07:24:10 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
after(async function () {
|
|
|
|
oldEnv.restore();
|
|
|
|
await server.restart();
|
|
|
|
});
|
|
|
|
|
|
|
|
async function enterCellWithoutWaitingOnServer(...keys: string[]) {
|
|
|
|
const lastKey = keys[keys.length - 1];
|
|
|
|
if (![Key.ENTER, Key.TAB, Key.DELETE].includes(lastKey)) {
|
|
|
|
keys.push(Key.ENTER);
|
|
|
|
}
|
|
|
|
await driver.sendKeys(...keys);
|
|
|
|
}
|
|
|
|
|
2023-10-31 13:07:02 +00:00
|
|
|
async function getNumWaiting() {
|
|
|
|
const cells = await gu.getVisibleDetailCells({col: 'Status', rowNums: [1, 2]});
|
|
|
|
return cells.map((cell) => {
|
|
|
|
const status = JSON.parse(cell.replace(/\n/g, ''));
|
|
|
|
return status.numWaiting;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
async function overflowWebhook() {
|
2023-07-18 07:24:10 +00:00
|
|
|
await gu.openPage('Table2');
|
|
|
|
await gu.getCell('A', 1).click();
|
2023-10-31 13:07:02 +00:00
|
|
|
await gu.enterCell(new Date().toString());
|
2023-07-18 07:24:10 +00:00
|
|
|
await gu.getCell('B', 1).click();
|
2023-10-31 13:07:02 +00:00
|
|
|
await enterCellWithoutWaitingOnServer(new Date().toString());
|
2023-07-26 10:20:20 +00:00
|
|
|
await gu.waitToPass(async () => {
|
|
|
|
const toast = await gu.getToasts();
|
|
|
|
assert.include(toast, 'New changes are temporarily suspended. Webhooks queue overflowed.' +
|
|
|
|
' Please check webhooks settings, remove invalid webhooks, and clean the queue.\ngo to webhook settings');
|
|
|
|
}, 4000);
|
2023-10-31 13:07:02 +00:00
|
|
|
}
|
2023-07-18 07:24:10 +00:00
|
|
|
|
2023-10-31 13:07:02 +00:00
|
|
|
async function overflowResolved() {
|
2023-07-18 07:24:10 +00:00
|
|
|
await gu.waitForServer();
|
2023-07-26 10:20:20 +00:00
|
|
|
await gu.waitToPass(async () => {
|
|
|
|
const toast = await gu.getToasts();
|
|
|
|
assert.notInclude(toast, 'New changes are temporarily suspended. Webhooks queue overflowed.' +
|
|
|
|
' Please check webhooks settings, remove invalid webhooks, and clean the queue.\ngo to webhook settings');
|
|
|
|
}, 12500);
|
2023-10-31 13:07:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
it('should show a message when overflowed', async function () {
|
|
|
|
await overflowWebhook();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('message should disappear after clearing queue', async function () {
|
|
|
|
await openWebhookPageWithoutWaitForServer();
|
|
|
|
assert.deepEqual(await getNumWaiting(), [2, 2]);
|
|
|
|
await driver.findContent('button', /Clear Queue/).click();
|
|
|
|
await overflowResolved();
|
|
|
|
assert.deepEqual(await getNumWaiting(), [0, 0]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should clear a single webhook queue when that webhook is disabled', async function () {
|
|
|
|
await overflowWebhook();
|
|
|
|
await openWebhookPageWithoutWaitForServer();
|
|
|
|
await gu.waitToPass(async () => {
|
|
|
|
assert.deepEqual(await getNumWaiting(), [2, 2]);
|
|
|
|
}, 4000);
|
|
|
|
await gu.getDetailCell({col: 'Enabled', rowNum: 1}).click();
|
|
|
|
await overflowResolved();
|
|
|
|
assert.deepEqual(await getNumWaiting(), [0, 2]);
|
2023-07-18 07:24:10 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
async function openWebhookPageWithoutWaitForServer() {
|
|
|
|
await openDocumentSettings();
|
2024-05-10 12:54:37 +00:00
|
|
|
const button = await driver.findContentWait('a', /Manage Webhooks/i, 3000);
|
2023-07-18 07:24:10 +00:00
|
|
|
await gu.scrollIntoView(button).click();
|
|
|
|
await waitForWebhookPage();
|
|
|
|
}
|
|
|
|
|
|
|
|
async function waitForWebhookPage() {
|
|
|
|
await driver.findContentWait('button', /Clear Queue/, 3000);
|
|
|
|
// No section, so no easy utility for setting focus. Click on a random cell.
|
|
|
|
await gu.getDetailCell({col: 'Webhook Id', rowNum: 1}).click();
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function openAccountMenu() {
|
|
|
|
await driver.findWait('.test-dm-account', 1000).click();
|
|
|
|
// Since the AccountWidget loads orgs and the user data asynchronously, the menu
|
|
|
|
// can expand itself causing the click to land on a wrong button.
|
|
|
|
await driver.findWait('.test-site-switcher-org', 1000);
|
|
|
|
await driver.sleep(250); // There's still some jitter (scroll-bar? other user accounts?)
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function openDocumentSettings() {
|
|
|
|
await openAccountMenu();
|
|
|
|
await driver.findContent('.grist-floating-menu a', 'Document Settings').click();
|
|
|
|
await gu.waitForUrl(/settings/, 5000);
|
|
|
|
}
|