@prostgles/app 2.3.6-dev.1789048658 → 2.3.6-dev.1789068015
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/build/js/main.bundle.js +1 -1
- package/dist/server/package.json +1 -1
- package/dist/server/src/ConnectionManager/ConnectionManager.d.ts.map +1 -1
- package/dist/server/src/ConnectionManager/ConnectionManager.js +13 -6
- package/dist/server/src/ConnectionManager/ConnectionManager.js.map +1 -1
- package/dist/server/src/ConnectionManager/getConnectionPublish.d.ts +1 -2
- package/dist/server/src/ConnectionManager/getConnectionPublish.d.ts.map +1 -1
- package/dist/server/src/ConnectionManager/getConnectionPublish.js +3 -5
- package/dist/server/src/ConnectionManager/getConnectionPublish.js.map +1 -1
- package/dist/server/src/ConnectionManager/getConnectionServerFunctions.d.ts.map +1 -1
- package/dist/server/src/ConnectionManager/getConnectionServerFunctions.js +6 -1
- package/dist/server/src/ConnectionManager/getConnectionServerFunctions.js.map +1 -1
- package/dist/server/src/ConnectionManager/getHotReloadConfigs.d.ts +4 -5
- package/dist/server/src/ConnectionManager/getHotReloadConfigs.d.ts.map +1 -1
- package/dist/server/src/ConnectionManager/getHotReloadConfigs.js +1 -10
- package/dist/server/src/ConnectionManager/getHotReloadConfigs.js.map +1 -1
- package/dist/server/src/ConnectionManager/startConnection.d.ts.map +1 -1
- package/dist/server/src/ConnectionManager/startConnection.js +2 -6
- package/dist/server/src/ConnectionManager/startConnection.js.map +1 -1
- package/dist/server/src/ConnectionManager/syncSchemaConfig.d.ts.map +1 -1
- package/dist/server/src/ConnectionManager/syncSchemaConfig.js +2 -9
- package/dist/server/src/ConnectionManager/syncSchemaConfig.js.map +1 -1
- package/dist/server/src/ConnectionManager/syncSchemaConfigAccessControl.d.ts +5 -0
- package/dist/server/src/ConnectionManager/syncSchemaConfigAccessControl.d.ts.map +1 -0
- package/dist/server/src/ConnectionManager/syncSchemaConfigAccessControl.js +108 -0
- package/dist/server/src/ConnectionManager/syncSchemaConfigAccessControl.js.map +1 -0
- package/dist/server/src/cli/cliTemplateFiles.js +3 -3
- package/dist/server/src/cli/cliTemplateFiles.js.map +1 -1
- package/dist/server/src/schemaConfig.d.ts +18 -3
- package/dist/server/src/schemaConfig.d.ts.map +1 -1
- package/dist/server/src/schemaConfig.js.map +1 -1
- package/dist/server/src/serverFunctions/insertConfigWorkspaces.d.ts +2 -1
- package/dist/server/src/serverFunctions/insertConfigWorkspaces.d.ts.map +1 -1
- package/dist/server/src/serverFunctions/insertConfigWorkspaces.js +14 -8
- package/dist/server/src/serverFunctions/insertConfigWorkspaces.js.map +1 -1
- package/dist/server/src/tableConfig/tableConfigLlm/tableConfigLlm.js +1 -1
- package/dist/server/src/tableConfig/tableConfigLlm/tableConfigLlm.js.map +1 -1
- package/dist/server/src/tableHooks/tableHooks.d.ts.map +1 -1
- package/dist/server/src/tableHooks/tableHooks.js +0 -2
- package/dist/server/src/tableHooks/tableHooks.js.map +1 -1
- package/package.json +1 -1
- package/dist/common/constants.d.ts.map +0 -1
- package/dist/common/constants.js.map +0 -1
- package/dist/e2e/shared/Testing.d.ts +0 -665
- package/dist/e2e/shared/Testing.js +0 -584
- package/dist/e2e/shared/constants.d.ts +0 -19
- package/dist/e2e/shared/constants.js +0 -23
- package/dist/e2e/shared/fixtures.d.ts +0 -4
- package/dist/e2e/shared/fixtures.js +0 -40
- package/dist/e2e/shared/goTo.d.ts +0 -2
- package/dist/e2e/shared/goTo.js +0 -85
- package/dist/e2e/shared/utils/constants.d.ts +0 -19
- package/dist/e2e/shared/utils/constants.js +0 -23
- package/dist/e2e/shared/utils/goTo.d.ts +0 -2
- package/dist/e2e/shared/utils/goTo.js +0 -85
- package/dist/e2e/shared/utils/utils.d.ts +0 -144
- package/dist/e2e/shared/utils/utils.js +0 -1041
- package/dist/e2e/shared/utils.d.ts +0 -144
- package/dist/e2e/shared/utils.js +0 -1041
- package/dist/e2e/tests/Testing.d.ts +0 -665
- package/dist/e2e/tests/Testing.d.ts.map +0 -1
- package/dist/e2e/tests/Testing.js +0 -584
- package/dist/e2e/tests/Testing.js.map +0 -1
- package/dist/e2e/tests/fixtures.d.ts +0 -4
- package/dist/e2e/tests/fixtures.d.ts.map +0 -1
- package/dist/e2e/tests/fixtures.js +0 -40
- package/dist/e2e/tests/fixtures.js.map +0 -1
- package/dist/e2e/tests/utils/constants.d.ts.map +0 -1
- package/dist/e2e/tests/utils/constants.js.map +0 -1
- package/dist/e2e/tests/utils/goTo.d.ts.map +0 -1
- package/dist/e2e/tests/utils/goTo.js.map +0 -1
- package/dist/e2e/tests/utils/utils.d.ts.map +0 -1
- package/dist/e2e/tests/utils/utils.js.map +0 -1
- package/dist/server/src/cli/testing/e2e/index.d.ts +0 -18
- package/dist/server/src/cli/testing/e2e/index.d.ts.map +0 -1
- package/dist/server/src/cli/testing/e2e/index.js +0 -70
- package/dist/server/src/cli/testing/e2e/index.js.map +0 -1
- package/dist/server/src/cli/testing/e2e/template.d.ts +0 -13
- package/dist/server/src/cli/testing/e2e/template.d.ts.map +0 -1
- package/dist/server/src/cli/testing/e2e/template.js +0 -57
- package/dist/server/src/cli/testing/e2e/template.js.map +0 -1
- package/dist/server/src/cli/testing/ui/index.d.ts +0 -7
- package/dist/server/src/cli/testing/ui/index.d.ts.map +0 -1
- package/dist/server/src/cli/testing/ui/index.js +0 -67
- package/dist/server/src/cli/testing/ui/index.js.map +0 -1
- package/dist/server/src/cli/testing/ui/template.d.ts +0 -13
- package/dist/server/src/cli/testing/ui/template.d.ts.map +0 -1
- package/dist/server/src/cli/testing/ui/template.js +0 -49
- package/dist/server/src/cli/testing/ui/template.js.map +0 -1
- package/dist/server/src/tableHooks/accessControl.tableHooks.d.ts +0 -4
- package/dist/server/src/tableHooks/accessControl.tableHooks.d.ts.map +0 -1
- package/dist/server/src/tableHooks/accessControl.tableHooks.js +0 -54
- package/dist/server/src/tableHooks/accessControl.tableHooks.js.map +0 -1
package/dist/e2e/shared/utils.js
DELETED
|
@@ -1,1041 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.deleteAllWorkspaces = exports.deleteExistingLLMChat = exports.setupProstglesLLMProvider = exports.setModelByText = exports.setPromptByText = exports.getDashboardUtils = exports.restoreFromBackup = exports.loginWhenSignupIsEnabled = exports.openConnection = exports.toggleMCPTools = exports.getLLMResponses = exports.sendAskLLMMessage = exports.getAskLLMLastMessage = exports.enableAskLLM = exports.createAccessRuleForTestDB = exports.createAccessRule = exports.disablePwdlessAdminAndCreateUser = exports.setWspColLayout = exports.getTableWindow = exports.getSearchListItem = exports.isEmpty = exports.uploadFile = exports.fileName = exports.TWENTY_SECONDS_OR_MORE = exports.getTimeout = exports.selectAndUpsertFile = exports.dropConnectionAndDatabase = exports.createDatabase = exports.MINUTE = exports.addExistingDatabase = exports.openTable = exports.runDbSql = exports.runDbsMethod = exports.runDbsSql = exports.setTableRule = exports.getSelector = exports.getTestId = exports.closeWorkspaceWindows = exports.forEachLocator = exports.typeConfirmationCode = exports.login = exports.fillLoginFormAndSubmit = exports.insertRow = exports.clickInsertRow = exports.fillSmartFormAndInsert = exports.fillSmartForm = exports.runSql = exports.monacoType = exports.getMonacoValue = exports.getMonacoEditorBySelector = void 0;
|
|
37
|
-
exports.allowOnce = exports.deletePreviousMessages = exports.enableMCPServers = exports.clickAndWait = exports.setupMagicLinkAuth = exports.newChat = exports.setOrAddWorkspace = void 0;
|
|
38
|
-
exports.scrollElementIntoView = scrollElementIntoView;
|
|
39
|
-
const test_1 = require("@playwright/test");
|
|
40
|
-
const path = __importStar(require("path"));
|
|
41
|
-
const Testing_1 = require("./Testing");
|
|
42
|
-
const goTo_1 = require("./goTo");
|
|
43
|
-
const constants_1 = require("./constants");
|
|
44
|
-
const getMonacoEditorBySelector = async (page, parentSelector) => {
|
|
45
|
-
const monacoEditor = await page
|
|
46
|
-
.locator(`${parentSelector} .monaco-editor`)
|
|
47
|
-
.first();
|
|
48
|
-
return monacoEditor;
|
|
49
|
-
};
|
|
50
|
-
exports.getMonacoEditorBySelector = getMonacoEditorBySelector;
|
|
51
|
-
const getMonacoValue = async (page, parentSelector) => {
|
|
52
|
-
await page.keyboard.press("Control+A");
|
|
53
|
-
await page.waitForTimeout(1500);
|
|
54
|
-
const monacoNode = await (0, exports.getMonacoEditorBySelector)(page, parentSelector);
|
|
55
|
-
const text = await monacoNode.evaluate((node) => {
|
|
56
|
-
//@ts-ignore
|
|
57
|
-
return node.parentElement._getValue();
|
|
58
|
-
});
|
|
59
|
-
// const text = await page.evaluate(
|
|
60
|
-
// () => window.getSelection()?.toString() ?? "",
|
|
61
|
-
// );
|
|
62
|
-
const normalizedText = text?.replace(/\u00A0/g, " "); // Replace char 160 with char 32
|
|
63
|
-
return normalizedText;
|
|
64
|
-
};
|
|
65
|
-
exports.getMonacoValue = getMonacoValue;
|
|
66
|
-
/**
|
|
67
|
-
* Will overwrite all previous content
|
|
68
|
-
*/
|
|
69
|
-
const monacoType = async (page, parentSelector, text, { deleteAll, deleteAllAndFill, pressBeforeTyping, pressAfterTyping, keyPressDelay = 100, } = { deleteAll: true }) => {
|
|
70
|
-
const monacoEditor = await (0, exports.getMonacoEditorBySelector)(page, parentSelector);
|
|
71
|
-
await monacoEditor.click();
|
|
72
|
-
await page.waitForTimeout(500);
|
|
73
|
-
if (deleteAll || deleteAllAndFill) {
|
|
74
|
-
await page.keyboard.press("Control+A");
|
|
75
|
-
await page.waitForTimeout(500);
|
|
76
|
-
await page.keyboard.press("Delete");
|
|
77
|
-
}
|
|
78
|
-
await page.waitForTimeout(500);
|
|
79
|
-
await monacoEditor.click();
|
|
80
|
-
await monacoEditor.blur();
|
|
81
|
-
await page.waitForTimeout(500);
|
|
82
|
-
await monacoEditor.click();
|
|
83
|
-
await page.waitForTimeout(500);
|
|
84
|
-
for (const key of pressBeforeTyping ?? []) {
|
|
85
|
-
await page.keyboard.press(key);
|
|
86
|
-
await page.waitForTimeout(50);
|
|
87
|
-
}
|
|
88
|
-
if (!keyPressDelay) {
|
|
89
|
-
await monacoEditor.evaluate((node, text) => {
|
|
90
|
-
//@ts-ignore
|
|
91
|
-
console.log(node.parentElement.editorRef);
|
|
92
|
-
//@ts-ignore
|
|
93
|
-
node.parentElement.editorRef.setValue(text);
|
|
94
|
-
}, text);
|
|
95
|
-
// await monacoEditor.fill(text, { force: true });
|
|
96
|
-
}
|
|
97
|
-
else if (deleteAllAndFill) {
|
|
98
|
-
await page.keyboard.insertText(text);
|
|
99
|
-
}
|
|
100
|
-
else {
|
|
101
|
-
await page.keyboard.type(text, { delay: keyPressDelay });
|
|
102
|
-
}
|
|
103
|
-
for (const key of pressAfterTyping ?? []) {
|
|
104
|
-
await page.keyboard.press(key);
|
|
105
|
-
await page.waitForTimeout(50);
|
|
106
|
-
}
|
|
107
|
-
await page.waitForTimeout(500);
|
|
108
|
-
};
|
|
109
|
-
exports.monacoType = monacoType;
|
|
110
|
-
const runSql = async (page, query) => {
|
|
111
|
-
await (0, exports.monacoType)(page, `.ProstglesSQL`, query);
|
|
112
|
-
await page.waitForTimeout(300);
|
|
113
|
-
await page.getByTestId("W_SQLBottomBar.runQuery").click();
|
|
114
|
-
await page.waitForTimeout(200);
|
|
115
|
-
await page.getByTestId("W_SQLBottomBar.runQuery").isEnabled({ timeout: 5e3 });
|
|
116
|
-
await page.waitForTimeout(1e3);
|
|
117
|
-
};
|
|
118
|
-
exports.runSql = runSql;
|
|
119
|
-
const fillSmartForm = async (page, tableName, values) => {
|
|
120
|
-
const smartFormLocator = `${(0, exports.getTestId)("SmartForm")}${(0, Testing_1.getDataKey)(tableName)}`;
|
|
121
|
-
for (const [key, valueOrRowOrRows] of Object.entries(values)) {
|
|
122
|
-
const unescapedSelector = `${tableName}-${key}`;
|
|
123
|
-
const escapedSelector = await page.evaluate((unescapedSelector) => CSS.escape(unescapedSelector), unescapedSelector);
|
|
124
|
-
if (typeof valueOrRowOrRows === "string") {
|
|
125
|
-
const value = valueOrRowOrRows;
|
|
126
|
-
const elem = await page.locator("input#" + escapedSelector);
|
|
127
|
-
await elem.fill(value);
|
|
128
|
-
const selectElem = await page.locator(`[data-key=${JSON.stringify(key)}] .FormField_Select`);
|
|
129
|
-
if (await selectElem.isVisible()) {
|
|
130
|
-
await selectElem.click();
|
|
131
|
-
await page
|
|
132
|
-
.getByTestId("SearchList.List")
|
|
133
|
-
.locator(`[data-key=${JSON.stringify(value)}]`)
|
|
134
|
-
.click();
|
|
135
|
-
}
|
|
136
|
-
/** Joined records */
|
|
137
|
-
}
|
|
138
|
-
else if (Array.isArray(valueOrRowOrRows)) {
|
|
139
|
-
const nestedTableName = key;
|
|
140
|
-
// const tabItem = await page.locator(
|
|
141
|
-
// `${smartFormLocator} ${getTestId("JoinedRecords")} ${getDataKey(nestedTableName)}`,
|
|
142
|
-
// );
|
|
143
|
-
// const isActive = await tabItem.getAttribute("aria-current");
|
|
144
|
-
// if (isActive !== "true") {
|
|
145
|
-
// await tabItem.click();
|
|
146
|
-
// }
|
|
147
|
-
for (const nestedRow of valueOrRowOrRows) {
|
|
148
|
-
await page
|
|
149
|
-
.locator(`${(0, exports.getTestId)("JoinedRecords.AddRow")}${(0, Testing_1.getDataKey)(nestedTableName)}`)
|
|
150
|
-
.click();
|
|
151
|
-
await (0, exports.fillSmartFormAndInsert)(page, nestedTableName, nestedRow);
|
|
152
|
-
}
|
|
153
|
-
/** Nested insert into fkey */
|
|
154
|
-
}
|
|
155
|
-
else if (typeof valueOrRowOrRows === "object") {
|
|
156
|
-
const nestedInsertBtn = await page
|
|
157
|
-
.locator(`${(0, exports.getTestId)("SmartFormField")}${(0, Testing_1.getDataKey)(key)} ${(0, exports.getTestId)("SmartFormFieldOptions.NestedInsert")}`)
|
|
158
|
-
.first();
|
|
159
|
-
const nestedTableName = await nestedInsertBtn.getAttribute("data-key");
|
|
160
|
-
if (!nestedTableName)
|
|
161
|
-
throw `nestedTableName not found for ${key}`;
|
|
162
|
-
await nestedInsertBtn.click();
|
|
163
|
-
await (0, exports.fillSmartFormAndInsert)(page, nestedTableName, valueOrRowOrRows);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
return page.locator(smartFormLocator);
|
|
167
|
-
};
|
|
168
|
-
exports.fillSmartForm = fillSmartForm;
|
|
169
|
-
const fillSmartFormAndInsert = async (page, tableName, values) => {
|
|
170
|
-
const form = await (0, exports.fillSmartForm)(page, tableName, values);
|
|
171
|
-
await page.waitForTimeout(200);
|
|
172
|
-
await form.getByTestId("SmartForm.insert").click();
|
|
173
|
-
await page.waitForTimeout(1200);
|
|
174
|
-
await (0, test_1.expect)(form).not.toBeVisible((0, exports.getTimeout)(2 * exports.MINUTE));
|
|
175
|
-
};
|
|
176
|
-
exports.fillSmartFormAndInsert = fillSmartFormAndInsert;
|
|
177
|
-
const clickInsertRow = async (page, tableName, useTopBtn = false) => {
|
|
178
|
-
await page
|
|
179
|
-
.getByTestId(useTopBtn ?
|
|
180
|
-
"dashboard.window.rowInsertTop"
|
|
181
|
-
: "dashboard.window.rowInsert")
|
|
182
|
-
.and(page.locator(`[data-key=${JSON.stringify(tableName)}]`))
|
|
183
|
-
.click();
|
|
184
|
-
await page.waitForTimeout(200);
|
|
185
|
-
};
|
|
186
|
-
exports.clickInsertRow = clickInsertRow;
|
|
187
|
-
const insertRow = async (page, tableName, row, useTopBtn = false) => {
|
|
188
|
-
await (0, exports.clickInsertRow)(page, tableName, useTopBtn);
|
|
189
|
-
await (0, exports.fillSmartFormAndInsert)(page, tableName, row);
|
|
190
|
-
await page.waitForTimeout(2200);
|
|
191
|
-
};
|
|
192
|
-
exports.insertRow = insertRow;
|
|
193
|
-
const fillLoginFormAndSubmit = async (page, userNameAndPassword = "test_user") => {
|
|
194
|
-
await page.locator("#username").waitFor({ state: "visible", timeout: 30e3 });
|
|
195
|
-
await page.locator("#username").fill("");
|
|
196
|
-
await page.locator("#username").fill(userNameAndPassword);
|
|
197
|
-
const continueBtn = page.getByRole("button", { name: "Continue" });
|
|
198
|
-
let isContinueBtnVisible = false;
|
|
199
|
-
if (await continueBtn.count()) {
|
|
200
|
-
isContinueBtnVisible = true;
|
|
201
|
-
await continueBtn.click();
|
|
202
|
-
}
|
|
203
|
-
await page.locator("#password").fill(userNameAndPassword);
|
|
204
|
-
if (isContinueBtnVisible) {
|
|
205
|
-
await continueBtn.click();
|
|
206
|
-
}
|
|
207
|
-
else {
|
|
208
|
-
await page.getByRole("button", { name: "Sign in", exact: true }).click();
|
|
209
|
-
}
|
|
210
|
-
};
|
|
211
|
-
exports.fillLoginFormAndSubmit = fillLoginFormAndSubmit;
|
|
212
|
-
const login = async (page, userNameAndPassword = "test_user", url = "localhost:3004") => {
|
|
213
|
-
await (0, goTo_1.goTo)(page, url);
|
|
214
|
-
await (0, exports.fillLoginFormAndSubmit)(page, userNameAndPassword);
|
|
215
|
-
await page.locator("#username").waitFor({ state: "detached", timeout: 30e3 });
|
|
216
|
-
};
|
|
217
|
-
exports.login = login;
|
|
218
|
-
const typeConfirmationCode = async (page) => {
|
|
219
|
-
await page.waitForTimeout(200);
|
|
220
|
-
const code = await page.getByTitle("confirmation-code").textContent();
|
|
221
|
-
await page.waitForTimeout(200);
|
|
222
|
-
await page
|
|
223
|
-
.locator(`input[name="confirmation"]`)
|
|
224
|
-
.fill(code ?? "code not found on the page");
|
|
225
|
-
await page.waitForTimeout(200);
|
|
226
|
-
};
|
|
227
|
-
exports.typeConfirmationCode = typeConfirmationCode;
|
|
228
|
-
const forEachLocator = async (page, match, onMatch) => {
|
|
229
|
-
let items = [];
|
|
230
|
-
do {
|
|
231
|
-
items = await (await match()).all();
|
|
232
|
-
const firstItem = items[0];
|
|
233
|
-
if (firstItem) {
|
|
234
|
-
await onMatch(firstItem);
|
|
235
|
-
await page.waitForTimeout(220);
|
|
236
|
-
}
|
|
237
|
-
} while (items.length);
|
|
238
|
-
};
|
|
239
|
-
exports.forEachLocator = forEachLocator;
|
|
240
|
-
const closeWorkspaceWindows = async (page) => {
|
|
241
|
-
await (0, exports.forEachLocator)(page, () => page.getByTestId("dashboard.window.close"), async (closeBtn) => {
|
|
242
|
-
await closeBtn.click();
|
|
243
|
-
/** SQL windows need save or delete confirmation */
|
|
244
|
-
const deleteSqlBtn = await page.getByRole("button", {
|
|
245
|
-
name: "Delete",
|
|
246
|
-
exact: true,
|
|
247
|
-
});
|
|
248
|
-
if (await deleteSqlBtn.count()) {
|
|
249
|
-
await deleteSqlBtn.click();
|
|
250
|
-
}
|
|
251
|
-
await page.waitForTimeout(220);
|
|
252
|
-
});
|
|
253
|
-
const closeBtnsCount = await page
|
|
254
|
-
.getByTestId("dashboard.window.close")
|
|
255
|
-
.count();
|
|
256
|
-
if (closeBtnsCount) {
|
|
257
|
-
throw `${closeBtnsCount} windows are still opened`;
|
|
258
|
-
}
|
|
259
|
-
await page.waitForTimeout(100);
|
|
260
|
-
};
|
|
261
|
-
exports.closeWorkspaceWindows = closeWorkspaceWindows;
|
|
262
|
-
const getTestId = (testid) => `[data-command=${JSON.stringify(testid)}]`;
|
|
263
|
-
exports.getTestId = getTestId;
|
|
264
|
-
const getSelector = ({ testid, dataKey, }) => [
|
|
265
|
-
testid && `[data-command=${JSON.stringify(testid)}]`,
|
|
266
|
-
dataKey && `[data-key=${JSON.stringify(dataKey)}]`,
|
|
267
|
-
]
|
|
268
|
-
.filter(Boolean)
|
|
269
|
-
.join("");
|
|
270
|
-
exports.getSelector = getSelector;
|
|
271
|
-
const setTableRule = async (page, tableName, rule, isFileTable) => {
|
|
272
|
-
const tableRow = await page.locator((0, Testing_1.getDataKey)(tableName));
|
|
273
|
-
const addSmartFilter = async ({ fieldName, value, }) => {
|
|
274
|
-
await page.getByTestId("SmartAddFilter").click();
|
|
275
|
-
await page.locator((0, Testing_1.getDataKey)(fieldName)).click();
|
|
276
|
-
const filterWrapperSelector = `${(0, exports.getTestId)("FilterWrapper")}${(0, Testing_1.getDataKey)(fieldName)}`;
|
|
277
|
-
await page
|
|
278
|
-
.locator(`${filterWrapperSelector} input[type="text"]`)
|
|
279
|
-
.fill(value);
|
|
280
|
-
await page.waitForTimeout(500);
|
|
281
|
-
await page.keyboard.press("Enter");
|
|
282
|
-
await page.waitForTimeout(200);
|
|
283
|
-
};
|
|
284
|
-
const setForcedFilter = async (forcedFilter) => {
|
|
285
|
-
if (!forcedFilter)
|
|
286
|
-
return;
|
|
287
|
-
await page.getByTestId("ForcedFilterControl.type").click();
|
|
288
|
-
await page.getByTestId("ForcedFilterControl.type.enabled").click();
|
|
289
|
-
for (const { fieldName, value } of forcedFilter) {
|
|
290
|
-
await addSmartFilter({ fieldName, value });
|
|
291
|
-
}
|
|
292
|
-
};
|
|
293
|
-
const setExcludedFields = async (excludedFields) => {
|
|
294
|
-
if (!excludedFields?.length)
|
|
295
|
-
return;
|
|
296
|
-
await page.getByTestId("FieldFilterControl.type").click();
|
|
297
|
-
await page.getByTestId("FieldFilterControl.type.except").click();
|
|
298
|
-
await page.getByTestId("FieldFilterControl.select").click();
|
|
299
|
-
await page.getByTestId("SearchList.toggleAll").click();
|
|
300
|
-
for (const field of excludedFields) {
|
|
301
|
-
await page.locator(`[data-key=${JSON.stringify(field)}]`).click();
|
|
302
|
-
await page.waitForTimeout(500);
|
|
303
|
-
}
|
|
304
|
-
await page.keyboard.press("Escape");
|
|
305
|
-
};
|
|
306
|
-
const setForcedData = async (forcedData) => {
|
|
307
|
-
if (!forcedData)
|
|
308
|
-
return;
|
|
309
|
-
// await page.getByTestId("ForcedDataControl.toggle").click();
|
|
310
|
-
// for(const [fieldName, value] of Object.entries(forcedData)){
|
|
311
|
-
// await page.getByTestId("ForcedDataControl.addColumn").click();
|
|
312
|
-
// await page.locator(`[data-key=${JSON.stringify(fieldName)}]`).click();
|
|
313
|
-
// await page.locator(`input#${tableName}-${fieldName}`).type(value);
|
|
314
|
-
// await page.waitForTimeout(500);
|
|
315
|
-
// }
|
|
316
|
-
await page.getByTestId("CheckFilterControl.type").click();
|
|
317
|
-
await page.getByTestId("CheckFilterControl.type.enabled").click();
|
|
318
|
-
for (const [fieldName, value] of Object.entries(forcedData)) {
|
|
319
|
-
await addSmartFilter({ fieldName, value });
|
|
320
|
-
}
|
|
321
|
-
};
|
|
322
|
-
const toggleFileRule = async () => {
|
|
323
|
-
const ruleToggle = await page.getByTestId("RuleToggle");
|
|
324
|
-
if (isFileTable) {
|
|
325
|
-
await ruleToggle.click();
|
|
326
|
-
await page.getByTestId("TablePermissionControls.close").click();
|
|
327
|
-
}
|
|
328
|
-
};
|
|
329
|
-
if (rule.select) {
|
|
330
|
-
await tableRow.getByTestId("selectRule").click();
|
|
331
|
-
await toggleFileRule();
|
|
332
|
-
await page.waitForTimeout(500);
|
|
333
|
-
if (!(0, exports.isEmpty)(rule.select)) {
|
|
334
|
-
await tableRow.getByTestId("selectRuleAdvanced").click();
|
|
335
|
-
await setExcludedFields(rule.select.excludedFields);
|
|
336
|
-
await setForcedFilter(rule.select.forcedFilter);
|
|
337
|
-
await page.getByTestId("TablePermissionControls.close").click();
|
|
338
|
-
await page.waitForTimeout(500);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
if (rule.insert) {
|
|
342
|
-
await tableRow.getByTestId("insertRule").click();
|
|
343
|
-
await toggleFileRule();
|
|
344
|
-
await page.waitForTimeout(500);
|
|
345
|
-
if (!(0, exports.isEmpty)(rule.select)) {
|
|
346
|
-
await tableRow.getByTestId("insertRuleAdvanced").click();
|
|
347
|
-
await setExcludedFields(rule.insert.excludedFields);
|
|
348
|
-
await setForcedData(rule.insert.forcedData);
|
|
349
|
-
await page.getByTestId("TablePermissionControls.close").click();
|
|
350
|
-
await page.waitForTimeout(500);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
if (rule.update) {
|
|
354
|
-
await tableRow.getByTestId("updateRule").click();
|
|
355
|
-
await toggleFileRule();
|
|
356
|
-
await page.waitForTimeout(500);
|
|
357
|
-
if (!(0, exports.isEmpty)(rule.select)) {
|
|
358
|
-
await tableRow.getByTestId("updateRuleAdvanced").click();
|
|
359
|
-
await setExcludedFields(rule.update.excludedFields);
|
|
360
|
-
await setForcedFilter(rule.update.forcedFilter);
|
|
361
|
-
await setForcedData(rule.update.forcedData);
|
|
362
|
-
await page.getByTestId("TablePermissionControls.close").click();
|
|
363
|
-
await page.waitForTimeout(500);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
if (rule.delete) {
|
|
367
|
-
await tableRow.getByTestId("deleteRule").click();
|
|
368
|
-
await toggleFileRule();
|
|
369
|
-
await page.waitForTimeout(500);
|
|
370
|
-
if (!(0, exports.isEmpty)(rule.select)) {
|
|
371
|
-
await tableRow.getByTestId("deleteRuleAdvanced").click();
|
|
372
|
-
await setForcedFilter(rule.delete.forcedFilter);
|
|
373
|
-
await page.getByTestId("TablePermissionControls.close").click();
|
|
374
|
-
await page.waitForTimeout(500);
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
await page.waitForTimeout(500);
|
|
378
|
-
};
|
|
379
|
-
exports.setTableRule = setTableRule;
|
|
380
|
-
const runDbsSql = async (page, query, args, opts) => {
|
|
381
|
-
return (0, exports.runDbSql)(page, query, args, opts, "dbs");
|
|
382
|
-
};
|
|
383
|
-
exports.runDbsSql = runDbsSql;
|
|
384
|
-
const runDbsMethod = async (page, methodName, args) => {
|
|
385
|
-
/** Wait for dbsMethod to become available */
|
|
386
|
-
await page.waitForFunction(() => {
|
|
387
|
-
return window.dbsMethods !== undefined;
|
|
388
|
-
});
|
|
389
|
-
const result = await page.evaluate(async ([methodName, args]) => {
|
|
390
|
-
const dbsMethods = window.dbsMethods;
|
|
391
|
-
if (!dbsMethods)
|
|
392
|
-
throw "dbsMethods is missing";
|
|
393
|
-
const method = dbsMethods[methodName];
|
|
394
|
-
if (!method)
|
|
395
|
-
throw `Method ${methodName} is missing in dbsMethods`;
|
|
396
|
-
const [data, err] = await method(args)
|
|
397
|
-
.then((data) => [data, undefined])
|
|
398
|
-
.catch((err) => {
|
|
399
|
-
console.error(`Error running dbs method ${methodName}:`, err);
|
|
400
|
-
return [undefined, err];
|
|
401
|
-
});
|
|
402
|
-
return [data, err];
|
|
403
|
-
}, [methodName, args]);
|
|
404
|
-
const [data, err] = result;
|
|
405
|
-
if (err) {
|
|
406
|
-
throw err;
|
|
407
|
-
}
|
|
408
|
-
return data;
|
|
409
|
-
};
|
|
410
|
-
exports.runDbsMethod = runDbsMethod;
|
|
411
|
-
const runDbSql = async (page, query, args, opts, dbType = "db") => {
|
|
412
|
-
/** Wait for handle to become available */
|
|
413
|
-
await page.waitForFunction(({ dbType }) => {
|
|
414
|
-
return window[dbType] !== undefined;
|
|
415
|
-
}, { dbType });
|
|
416
|
-
const [error, sqlResult] = (await page.evaluate(async ([query, args, opts, dbType]) => {
|
|
417
|
-
try {
|
|
418
|
-
const sql = window[dbType === "db" ? "sql" : "dbsSql"];
|
|
419
|
-
if (!sql)
|
|
420
|
-
throw dbType === "db" ? "db is missing" : "dbs is missing";
|
|
421
|
-
const data = await sql(query, args, opts);
|
|
422
|
-
return [undefined, data];
|
|
423
|
-
}
|
|
424
|
-
catch (error) {
|
|
425
|
-
return [error];
|
|
426
|
-
}
|
|
427
|
-
}, [query, args, opts, dbType]));
|
|
428
|
-
if (error) {
|
|
429
|
-
console.error(`Error running sql:`, error);
|
|
430
|
-
throw error;
|
|
431
|
-
}
|
|
432
|
-
return sqlResult;
|
|
433
|
-
};
|
|
434
|
-
exports.runDbSql = runDbSql;
|
|
435
|
-
const openTable = async (page, namePartStart, exact = false) => {
|
|
436
|
-
await page.getByTestId("dashboard.menu").waitFor({ state: "visible" });
|
|
437
|
-
await page.keyboard.press("Control+KeyP");
|
|
438
|
-
await page.waitForTimeout(200);
|
|
439
|
-
const searchAlLInput = await page.getByTestId("SearchAll");
|
|
440
|
-
await searchAlLInput.waitFor({ state: "visible" });
|
|
441
|
-
await searchAlLInput.fill(namePartStart);
|
|
442
|
-
await page.waitForTimeout(200);
|
|
443
|
-
await page.keyboard.press("Enter");
|
|
444
|
-
await page.waitForTimeout(500);
|
|
445
|
-
/** Ensure table was opened */
|
|
446
|
-
const table = page.locator(`[data-table-name${exact ? "=" : "^="}${JSON.stringify(namePartStart)}]`);
|
|
447
|
-
/** Used for debugging */
|
|
448
|
-
if (!(await table.isVisible())) {
|
|
449
|
-
const v_triggers = await (0, exports.runDbsSql)(page, `SELECT * FROM prostgles.v_triggers;`, {}, { returnType: "rows" });
|
|
450
|
-
console.log(JSON.stringify({ v_triggers, namePartStart, expect: test_1.expect }));
|
|
451
|
-
await page.waitForTimeout(500);
|
|
452
|
-
}
|
|
453
|
-
await (0, test_1.expect)(table).toBeVisible();
|
|
454
|
-
await page.waitForTimeout(1000);
|
|
455
|
-
};
|
|
456
|
-
exports.openTable = openTable;
|
|
457
|
-
const addExistingDatabase = async (page, dbName) => {
|
|
458
|
-
await (0, goTo_1.goTo)(page, "localhost:3004/connections");
|
|
459
|
-
await page.getByTestId("ConnectionServer.add").click();
|
|
460
|
-
await page
|
|
461
|
-
.locator(`[data-label="Select a database from this server"]`)
|
|
462
|
-
.click();
|
|
463
|
-
await page.getByTestId("ConnectionServer.add.existingDatabase").click();
|
|
464
|
-
await page
|
|
465
|
-
.getByTestId("ConnectionServer.add.existingDatabase")
|
|
466
|
-
.locator((0, Testing_1.getDataKey)(dbName))
|
|
467
|
-
.click();
|
|
468
|
-
await page.getByTestId("ConnectionServer.add.confirm").click();
|
|
469
|
-
};
|
|
470
|
-
exports.addExistingDatabase = addExistingDatabase;
|
|
471
|
-
exports.MINUTE = 60e3;
|
|
472
|
-
const createDatabase = async (dbName, page, fromTemplates = false, owner) => {
|
|
473
|
-
await (0, goTo_1.goTo)(page, "localhost:3004/connections");
|
|
474
|
-
await page
|
|
475
|
-
.locator(`[data-command="ConnectionServer.add"][data-key^="usr@localhost"]`)
|
|
476
|
-
.first()
|
|
477
|
-
.click();
|
|
478
|
-
// await page.waitForTimeout(3000);
|
|
479
|
-
if (fromTemplates) {
|
|
480
|
-
await page.getByTestId("ConnectionServer.add.newDatabase").click();
|
|
481
|
-
await page.getByTestId("ConnectionServer.SampleSchemas").click();
|
|
482
|
-
await page
|
|
483
|
-
.getByTestId("ConnectionServer.SampleSchemas")
|
|
484
|
-
.locator(`[data-key=${JSON.stringify(dbName)}]`)
|
|
485
|
-
.click();
|
|
486
|
-
}
|
|
487
|
-
else {
|
|
488
|
-
await page.getByTestId("ConnectionServer.add.newDatabase").click();
|
|
489
|
-
await page
|
|
490
|
-
.getByTestId("ConnectionServer.NewDbName")
|
|
491
|
-
.locator("input")
|
|
492
|
-
.fill(dbName);
|
|
493
|
-
}
|
|
494
|
-
if (owner) {
|
|
495
|
-
await page.getByTestId("ConnectionServer.withNewOwnerToggle").click();
|
|
496
|
-
await page.waitForTimeout(500);
|
|
497
|
-
await page
|
|
498
|
-
.getByTestId("ConnectionServer.NewUserName")
|
|
499
|
-
.locator("input")
|
|
500
|
-
.fill(owner.name);
|
|
501
|
-
await page
|
|
502
|
-
.getByTestId("ConnectionServer.NewUserPassword")
|
|
503
|
-
.locator("input")
|
|
504
|
-
.fill(owner.pass);
|
|
505
|
-
await page.waitForTimeout(500);
|
|
506
|
-
}
|
|
507
|
-
await page.getByTestId("ConnectionServer.add.confirm").click();
|
|
508
|
-
/* Wait until db is created */
|
|
509
|
-
const databaseCreationTime = (fromTemplates ? 4 : 1) * exports.MINUTE;
|
|
510
|
-
const workspaceCreationAndLoatTime = 3 * exports.MINUTE;
|
|
511
|
-
await page
|
|
512
|
-
.getByTestId("ConnectionServer.add.confirm")
|
|
513
|
-
.waitFor({ state: "detached", timeout: databaseCreationTime });
|
|
514
|
-
await page
|
|
515
|
-
.getByTestId("dashboard.menu")
|
|
516
|
-
.waitFor({ state: "visible", timeout: workspaceCreationAndLoatTime });
|
|
517
|
-
};
|
|
518
|
-
exports.createDatabase = createDatabase;
|
|
519
|
-
const dropConnectionAndDatabase = async (dbName, page, andDatabase = true) => {
|
|
520
|
-
await page.waitForTimeout(2000);
|
|
521
|
-
const connectionSelector = `[data-key=${JSON.stringify(dbName)}]`;
|
|
522
|
-
await page.locator(connectionSelector).getByTestId("Connection.edit").click();
|
|
523
|
-
await page.getByTestId("Connection.edit.delete").click();
|
|
524
|
-
if (andDatabase) {
|
|
525
|
-
await page.getByTestId("Connection.edit.delete.dropDatabase").click();
|
|
526
|
-
}
|
|
527
|
-
await (0, exports.typeConfirmationCode)(page);
|
|
528
|
-
await page.getByTestId("Connection.edit.delete.confirm").click();
|
|
529
|
-
await page.waitForTimeout(5000);
|
|
530
|
-
return { connectionSelector };
|
|
531
|
-
};
|
|
532
|
-
exports.dropConnectionAndDatabase = dropConnectionAndDatabase;
|
|
533
|
-
const selectAndUpsertFile = async (page, onOpenFileDialog, onBeforePressInsert, isUpdate = false) => {
|
|
534
|
-
// Start waiting for file chooser before clicking. Note no await.
|
|
535
|
-
const fileChooserPromise = page.waitForEvent("filechooser");
|
|
536
|
-
await onOpenFileDialog(page);
|
|
537
|
-
const fileChooser = await fileChooserPromise;
|
|
538
|
-
const resolvedPath = path.resolve(path.join(__dirname, "../" + exports.fileName));
|
|
539
|
-
await fileChooser.setFiles(resolvedPath);
|
|
540
|
-
await onBeforePressInsert?.();
|
|
541
|
-
await page
|
|
542
|
-
.getByRole("button", { name: isUpdate ? "Update" : "Insert", exact: true })
|
|
543
|
-
.click();
|
|
544
|
-
if (isUpdate) {
|
|
545
|
-
await page
|
|
546
|
-
.getByRole("button", { name: "Update row!", exact: true })
|
|
547
|
-
.click();
|
|
548
|
-
}
|
|
549
|
-
};
|
|
550
|
-
exports.selectAndUpsertFile = selectAndUpsertFile;
|
|
551
|
-
const getTimeout = (base) => ({
|
|
552
|
-
timeout: base * (process.env.CI ? 3 : 1),
|
|
553
|
-
});
|
|
554
|
-
exports.getTimeout = getTimeout;
|
|
555
|
-
exports.TWENTY_SECONDS_OR_MORE = (0, exports.getTimeout)(20_000);
|
|
556
|
-
exports.fileName = "icon512.png";
|
|
557
|
-
const uploadFile = async (page) => {
|
|
558
|
-
await (0, exports.clickInsertRow)(page, "files");
|
|
559
|
-
await page.waitForTimeout(200);
|
|
560
|
-
await (0, exports.selectAndUpsertFile)(page, (page) => page.getByTestId("FileBtn").click());
|
|
561
|
-
const MINUTE = 60e3;
|
|
562
|
-
await page
|
|
563
|
-
.getByTestId("Popup.content")
|
|
564
|
-
.waitFor({ state: "detached", ...(0, exports.getTimeout)(2 * MINUTE) });
|
|
565
|
-
};
|
|
566
|
-
exports.uploadFile = uploadFile;
|
|
567
|
-
const isEmpty = (obj) => {
|
|
568
|
-
return !obj || Object.keys(obj).length === 0;
|
|
569
|
-
};
|
|
570
|
-
exports.isEmpty = isEmpty;
|
|
571
|
-
const getSearchListItem = (page, { dataKey }) => {
|
|
572
|
-
return page.getByTestId("SearchList.List").locator((0, Testing_1.getDataKey)(dataKey));
|
|
573
|
-
};
|
|
574
|
-
exports.getSearchListItem = getSearchListItem;
|
|
575
|
-
const getTableWindow = (page, tableName) => {
|
|
576
|
-
return page.locator(`[data-table-name=${JSON.stringify(tableName)}]`);
|
|
577
|
-
};
|
|
578
|
-
exports.getTableWindow = getTableWindow;
|
|
579
|
-
const setWspColLayout = async (page) => {
|
|
580
|
-
await page.getByTestId("dashboard.menu").waitFor({ state: "visible" });
|
|
581
|
-
await page.getByTestId("dashboard.menu.settingsToggle").click();
|
|
582
|
-
await page.getByTestId("dashboard.menu.settings.defaultLayoutType").click();
|
|
583
|
-
await page
|
|
584
|
-
.getByTestId("dashboard.menu.settings.defaultLayoutType")
|
|
585
|
-
.locator(`[data-key="col"]`)
|
|
586
|
-
.click();
|
|
587
|
-
await page.getByTestId("Popup.close").click();
|
|
588
|
-
};
|
|
589
|
-
exports.setWspColLayout = setWspColLayout;
|
|
590
|
-
const disablePwdlessAdminAndCreateUser = async (page) => {
|
|
591
|
-
await page
|
|
592
|
-
.getByRole("link", { name: "Users" })
|
|
593
|
-
.waitFor({ state: "visible", timeout: 60e3 });
|
|
594
|
-
await page.getByRole("link", { name: "Users" }).click();
|
|
595
|
-
await (0, test_1.expect)(page).toHaveURL(/.*users/);
|
|
596
|
-
// const currentUrl = page.url();
|
|
597
|
-
// await page.goto();
|
|
598
|
-
// await page.goto(`${currentUrl}users`, {
|
|
599
|
-
// waitUntil: "networkidle",
|
|
600
|
-
// timeout: 10e3,
|
|
601
|
-
// });
|
|
602
|
-
await page.getByRole("button", { name: "Create admin user" }).click();
|
|
603
|
-
await page.locator("#username").fill(constants_1.USERS.test_user);
|
|
604
|
-
await page.locator("#new-password").fill(constants_1.USERS.test_user);
|
|
605
|
-
await page.locator("#confirm_password").fill(constants_1.USERS.test_user);
|
|
606
|
-
await page.getByRole("button", { name: "Create", exact: true }).click();
|
|
607
|
-
await page.waitForTimeout(5e3);
|
|
608
|
-
};
|
|
609
|
-
exports.disablePwdlessAdminAndCreateUser = disablePwdlessAdminAndCreateUser;
|
|
610
|
-
const createAccessRule = async (page, userType) => {
|
|
611
|
-
/** Set permissions */
|
|
612
|
-
await page.getByTestId("config.ac").click();
|
|
613
|
-
await page.waitForTimeout(1e3);
|
|
614
|
-
await page.getByTestId("config.ac.create").click();
|
|
615
|
-
/** Setting user type to default */
|
|
616
|
-
await page.getByTestId("config.ac.edit.user").click();
|
|
617
|
-
await page.getByRole("option").getByText(userType).click();
|
|
618
|
-
await page.getByRole("button", { name: "Done", exact: true }).click();
|
|
619
|
-
/** Setting AC Type to custom */
|
|
620
|
-
await page
|
|
621
|
-
.getByTestId("config.ac.edit.type")
|
|
622
|
-
.locator(`button[value="Custom"]`)
|
|
623
|
-
.click();
|
|
624
|
-
};
|
|
625
|
-
exports.createAccessRule = createAccessRule;
|
|
626
|
-
const createAccessRuleForTestDB = async (page, userType) => {
|
|
627
|
-
await (0, exports.login)(page);
|
|
628
|
-
await page.getByRole("link", { name: "Connections" }).click();
|
|
629
|
-
await page.getByRole("link", { name: constants_1.TEST_DB_NAME }).click();
|
|
630
|
-
await page
|
|
631
|
-
.getByTestId("dashboard.goToConnConfig")
|
|
632
|
-
.waitFor({ state: "visible", timeout: 10e3 });
|
|
633
|
-
await page.getByTestId("dashboard.goToConnConfig").click();
|
|
634
|
-
await (0, exports.createAccessRule)(page, userType);
|
|
635
|
-
};
|
|
636
|
-
exports.createAccessRuleForTestDB = createAccessRuleForTestDB;
|
|
637
|
-
const enableAskLLM = async (page, maxRequestsPerDay, credsProvided = false) => {
|
|
638
|
-
await page.getByTestId("AskLLMAccessControl").click();
|
|
639
|
-
if (!credsProvided) {
|
|
640
|
-
await page.getByTestId("SetupLLMCredentials.api").click();
|
|
641
|
-
// await page.getByTestId("AddLLMCredentialForm").click();
|
|
642
|
-
await page.getByTestId("dashboard.window.rowInsertTop").click();
|
|
643
|
-
// await page.getByTestId("AddLLMCredentialForm.Provider").click();
|
|
644
|
-
// await page
|
|
645
|
-
// .getByTestId("AddLLMCredentialForm.Provider")
|
|
646
|
-
// .locator(`[data-key="Custom"]`)
|
|
647
|
-
// .click();
|
|
648
|
-
await (0, exports.runDbsSql)(page, "DELETE FROM llm_providers WHERE id = 'Custom' ");
|
|
649
|
-
await (0, exports.fillSmartFormAndInsert)(page, "llm_credentials", {
|
|
650
|
-
name: "my credential",
|
|
651
|
-
api_key: "nothing",
|
|
652
|
-
provider_id: {
|
|
653
|
-
id: "Custom",
|
|
654
|
-
api_url: "http://localhost:3004/mocked-llm",
|
|
655
|
-
logo_url: "/icons/CloudQuestionOutline.svg",
|
|
656
|
-
llm_models: [
|
|
657
|
-
{
|
|
658
|
-
name: "mymodel",
|
|
659
|
-
},
|
|
660
|
-
],
|
|
661
|
-
},
|
|
662
|
-
});
|
|
663
|
-
// await page.locator(`#endpoint`).fill("http://localhost:3004/mocked-llm");
|
|
664
|
-
// await page.getByTestId("AddLLMCredentialForm.Save").click();
|
|
665
|
-
}
|
|
666
|
-
await page.getByTestId("AskLLMAccessControl.AllowAll").click();
|
|
667
|
-
await page.waitForTimeout(1e3);
|
|
668
|
-
if (maxRequestsPerDay) {
|
|
669
|
-
await page
|
|
670
|
-
.getByTestId("AskLLMAccessControl.llm_daily_limit")
|
|
671
|
-
.locator("input")
|
|
672
|
-
.fill(maxRequestsPerDay.toString());
|
|
673
|
-
}
|
|
674
|
-
await page.getByTestId("Popup.close").click();
|
|
675
|
-
};
|
|
676
|
-
exports.enableAskLLM = enableAskLLM;
|
|
677
|
-
const getAskLLMLastMessage = async (page) => {
|
|
678
|
-
const lastIncomingMessage = page
|
|
679
|
-
.getByTestId("AskLLM.popup")
|
|
680
|
-
.locator(".message.incoming")
|
|
681
|
-
.last();
|
|
682
|
-
/** Await any in progress tool calls */
|
|
683
|
-
const toolCallBtns = await lastIncomingMessage
|
|
684
|
-
.getByTestId("ToolUseMessage.toggle")
|
|
685
|
-
.all();
|
|
686
|
-
await Promise.all([...toolCallBtns, lastIncomingMessage].map((btn) => btn
|
|
687
|
-
.getByTestId("Loading")
|
|
688
|
-
.waitFor({ state: "detached", timeout: 30_000 })));
|
|
689
|
-
await page.waitForTimeout(1500);
|
|
690
|
-
return lastIncomingMessage;
|
|
691
|
-
};
|
|
692
|
-
exports.getAskLLMLastMessage = getAskLLMLastMessage;
|
|
693
|
-
const waitForAllMatchingLocatorsToDisappear = async (locator, timeout = 30_000) => {
|
|
694
|
-
const start = Date.now();
|
|
695
|
-
let tries = 0;
|
|
696
|
-
while (true) {
|
|
697
|
-
const count = await locator.count();
|
|
698
|
-
if (!count) {
|
|
699
|
-
if (tries > 2) {
|
|
700
|
-
return;
|
|
701
|
-
}
|
|
702
|
-
else {
|
|
703
|
-
tries++;
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
else if (Date.now() - start > timeout) {
|
|
707
|
-
throw new Error(`Timeout waiting for locators to disappear. Still ${count} remaining.`);
|
|
708
|
-
}
|
|
709
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
710
|
-
}
|
|
711
|
-
};
|
|
712
|
-
const sendAskLLMMessage = async (page, msg, waitForLoadingToStop = false) => {
|
|
713
|
-
const textArea = page
|
|
714
|
-
.getByTestId("AskLLM.popup")
|
|
715
|
-
.getByTestId("Chat.textarea");
|
|
716
|
-
await (0, test_1.expect)(textArea).toBeEnabled(exports.TWENTY_SECONDS_OR_MORE);
|
|
717
|
-
await textArea.fill(msg);
|
|
718
|
-
await page.keyboard.press("Enter");
|
|
719
|
-
await page.waitForTimeout(500);
|
|
720
|
-
if (waitForLoadingToStop) {
|
|
721
|
-
if (typeof waitForLoadingToStop === "object") {
|
|
722
|
-
await waitForLoadingToStop.onAfterSend();
|
|
723
|
-
}
|
|
724
|
-
await waitForAllMatchingLocatorsToDisappear(page
|
|
725
|
-
.getByTestId("Chat.messageList")
|
|
726
|
-
.getByTestId("Loading")
|
|
727
|
-
// .locator(".message.incoming .Loading")
|
|
728
|
-
.last());
|
|
729
|
-
}
|
|
730
|
-
};
|
|
731
|
-
exports.sendAskLLMMessage = sendAskLLMMessage;
|
|
732
|
-
const getLLMResponses = async (page, questions, openWindow = true) => {
|
|
733
|
-
if (openWindow) {
|
|
734
|
-
await page.getByTestId("AskLLM").click();
|
|
735
|
-
}
|
|
736
|
-
await page.getByTestId("AskLLM.popup").waitFor({ state: "visible" });
|
|
737
|
-
await page.waitForTimeout(2e3);
|
|
738
|
-
const result = [];
|
|
739
|
-
for (const question of questions) {
|
|
740
|
-
await (0, exports.sendAskLLMMessage)(page, question);
|
|
741
|
-
const responseMessage = await (0, exports.getAskLLMLastMessage)(page);
|
|
742
|
-
const response = await responseMessage.textContent();
|
|
743
|
-
result.push({
|
|
744
|
-
response,
|
|
745
|
-
isOk: !!response?.includes("Mocked response"),
|
|
746
|
-
});
|
|
747
|
-
await page.waitForTimeout(3000);
|
|
748
|
-
}
|
|
749
|
-
if (openWindow) {
|
|
750
|
-
await page.getByTestId("Popup.close").click();
|
|
751
|
-
}
|
|
752
|
-
return result;
|
|
753
|
-
};
|
|
754
|
-
exports.getLLMResponses = getLLMResponses;
|
|
755
|
-
const toggleMCPTools = async (page, toolNames, toggleAutoApprove) => {
|
|
756
|
-
await page.getByTestId("LLMChatOptions.MCPTools").click({ timeout: 10e3 });
|
|
757
|
-
await page.waitForTimeout(1000);
|
|
758
|
-
for (const toolName of toolNames) {
|
|
759
|
-
await page
|
|
760
|
-
.getByTestId("LLMChatOptions.MCPTools")
|
|
761
|
-
.getByTestId("MCPServerTools")
|
|
762
|
-
.getByText(toolName, { exact: true })
|
|
763
|
-
.click({ timeout: 30e3 });
|
|
764
|
-
await page.waitForTimeout(1500);
|
|
765
|
-
}
|
|
766
|
-
if (toggleAutoApprove) {
|
|
767
|
-
const node = page.getByTestId("MCPServers.toggleAutoApprove");
|
|
768
|
-
await node.waitFor({ state: "visible", timeout: 10e3 });
|
|
769
|
-
if ((await node.textContent())?.includes(": ON")) {
|
|
770
|
-
await node.click();
|
|
771
|
-
}
|
|
772
|
-
await page.waitForTimeout(1000);
|
|
773
|
-
await node.click();
|
|
774
|
-
}
|
|
775
|
-
await page.getByTestId("Popup.close").last().click();
|
|
776
|
-
await page.waitForTimeout(500);
|
|
777
|
-
};
|
|
778
|
-
exports.toggleMCPTools = toggleMCPTools;
|
|
779
|
-
const openConnection = async (page, connectionName) => {
|
|
780
|
-
await (0, goTo_1.goTo)(page, "/connections");
|
|
781
|
-
await page
|
|
782
|
-
.locator((0, Testing_1.getDataKey)(connectionName))
|
|
783
|
-
.getByTestId("Connection.openConnection")
|
|
784
|
-
.click();
|
|
785
|
-
await page.waitForTimeout(1000);
|
|
786
|
-
};
|
|
787
|
-
exports.openConnection = openConnection;
|
|
788
|
-
const loginWhenSignupIsEnabled = async (page, userNameAndPassword = "test_user") => {
|
|
789
|
-
await (0, goTo_1.goTo)(page, "/login");
|
|
790
|
-
await page.locator("#username").fill(userNameAndPassword);
|
|
791
|
-
await page.getByRole("button", { name: "Continue" }).click();
|
|
792
|
-
await page.locator("#password").waitFor({ state: "visible" });
|
|
793
|
-
await page.locator("#password").fill(userNameAndPassword);
|
|
794
|
-
await page.getByRole("button", { name: "Continue" }).click();
|
|
795
|
-
await page.getByTestId("App.colorScheme").waitFor({ state: "visible" });
|
|
796
|
-
await page.waitForTimeout(500);
|
|
797
|
-
};
|
|
798
|
-
exports.loginWhenSignupIsEnabled = loginWhenSignupIsEnabled;
|
|
799
|
-
const backupNames = "Demo";
|
|
800
|
-
const restoreFromBackup = async (page, backupFileName) => {
|
|
801
|
-
const backupListItems = await page
|
|
802
|
-
.getByTestId("BackupsControls.Completed")
|
|
803
|
-
.locator(".SmartCard");
|
|
804
|
-
await backupListItems.first().waitFor({ state: "visible" });
|
|
805
|
-
const backupItem = backupFileName ?
|
|
806
|
-
backupListItems.filter({ hasText: `Backup name${backupFileName}` })
|
|
807
|
-
: backupListItems;
|
|
808
|
-
await backupItem
|
|
809
|
-
.getByRole("button", { name: "Restore...", exact: true })
|
|
810
|
-
.click();
|
|
811
|
-
await (0, exports.typeConfirmationCode)(page);
|
|
812
|
-
await page.getByRole("button", { name: "Restore", exact: true }).click();
|
|
813
|
-
};
|
|
814
|
-
exports.restoreFromBackup = restoreFromBackup;
|
|
815
|
-
const getDashboardUtils = (page) => {
|
|
816
|
-
const _open = exports.openConnection.bind(null, page);
|
|
817
|
-
const openMenuIfClosed = async (closeMenu = false) => {
|
|
818
|
-
await page.waitForTimeout(1500);
|
|
819
|
-
const menuCloseButton = await page
|
|
820
|
-
.getByTestId("DashboardMenu")
|
|
821
|
-
.getByTestId("Popup.close");
|
|
822
|
-
const menuPinnedButton = await page.locator((0, Testing_1.getCommandElemSelector)("DashboardMenuHeader.togglePinned") +
|
|
823
|
-
(0, Testing_1.getDataKey)("pinned"));
|
|
824
|
-
const menuIsOpen = (await menuCloseButton.count()) ? "close"
|
|
825
|
-
: (await menuPinnedButton.count()) ? "unpinn"
|
|
826
|
-
: undefined;
|
|
827
|
-
if (menuIsOpen) {
|
|
828
|
-
if (closeMenu) {
|
|
829
|
-
if (menuIsOpen === "close") {
|
|
830
|
-
await menuCloseButton.click();
|
|
831
|
-
}
|
|
832
|
-
else {
|
|
833
|
-
await menuPinnedButton.click();
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
return;
|
|
837
|
-
}
|
|
838
|
-
const menuBtn = await page.getByTestId("dashboard.menu");
|
|
839
|
-
if ((await menuBtn.count()) && (await menuBtn.isEnabled())) {
|
|
840
|
-
await menuBtn.click();
|
|
841
|
-
}
|
|
842
|
-
};
|
|
843
|
-
const toggleMenuPinned = async (shouldBePinned) => {
|
|
844
|
-
await page.waitForTimeout(1500);
|
|
845
|
-
const toggleBtn = await page.getByTestId("DashboardMenuHeader.togglePinned");
|
|
846
|
-
const menuBtn = await page.getByTestId("dashboard.menu");
|
|
847
|
-
const menuIsPinned = await menuBtn.isDisabled();
|
|
848
|
-
if ((await toggleBtn.count()) && (await toggleBtn.isEnabled())) {
|
|
849
|
-
if (menuIsPinned && shouldBePinned) {
|
|
850
|
-
return;
|
|
851
|
-
}
|
|
852
|
-
await toggleBtn.click();
|
|
853
|
-
}
|
|
854
|
-
else if (shouldBePinned) {
|
|
855
|
-
await menuBtn.click();
|
|
856
|
-
await page.getByTestId("DashboardMenuHeader.togglePinned").click();
|
|
857
|
-
}
|
|
858
|
-
};
|
|
859
|
-
return {
|
|
860
|
-
openConnection: _open,
|
|
861
|
-
openMenuIfClosed,
|
|
862
|
-
toggleMenuPinned,
|
|
863
|
-
};
|
|
864
|
-
};
|
|
865
|
-
exports.getDashboardUtils = getDashboardUtils;
|
|
866
|
-
const setPromptByText = async (page, text, closePopup = true) => {
|
|
867
|
-
await page.getByTestId("LLMChatOptions.Prompt").click();
|
|
868
|
-
const promptBtn = page
|
|
869
|
-
.locator(".SmartCard button", { hasText: text })
|
|
870
|
-
.first();
|
|
871
|
-
if ((await promptBtn.getAttribute("data-color")) !== "action") {
|
|
872
|
-
await promptBtn.click();
|
|
873
|
-
await (0, test_1.expect)(promptBtn).not.toBeDisabled(exports.TWENTY_SECONDS_OR_MORE);
|
|
874
|
-
}
|
|
875
|
-
await page.waitForTimeout(3e3); // wait for prompt tools to be set
|
|
876
|
-
if (!closePopup)
|
|
877
|
-
return;
|
|
878
|
-
await page
|
|
879
|
-
.getByTestId("LLMChatOptions.Prompt")
|
|
880
|
-
.getByTestId("Popup.close")
|
|
881
|
-
.click();
|
|
882
|
-
};
|
|
883
|
-
exports.setPromptByText = setPromptByText;
|
|
884
|
-
const setModelByText = async (page, text) => {
|
|
885
|
-
await page.getByTestId("LLMChatOptions.Model").click();
|
|
886
|
-
await page.waitForTimeout(500);
|
|
887
|
-
await page.keyboard.type(text);
|
|
888
|
-
await page.keyboard.press("Enter");
|
|
889
|
-
await page.waitForTimeout(1e3); // wait for model to be set
|
|
890
|
-
};
|
|
891
|
-
exports.setModelByText = setModelByText;
|
|
892
|
-
const setupProstglesLLMProvider = async (page) => {
|
|
893
|
-
const aiDemoDBName = "prostgles_video_demo";
|
|
894
|
-
await (0, exports.openConnection)(page, "cloud");
|
|
895
|
-
await (0, exports.openConnection)(page, aiDemoDBName);
|
|
896
|
-
await (0, exports.runDbsSql)(page, "TRUNCATE llm_chats CASCADE");
|
|
897
|
-
await (0, exports.runDbsSql)(page, `
|
|
898
|
-
DELETE FROM llm_credentials WHERE provider_id = 'Prostgles';
|
|
899
|
-
UPDATE llm_providers
|
|
900
|
-
SET api_url = 'http://localhost:3005/rest-api/methods/askLLM'
|
|
901
|
-
WHERE id = 'Prostgles';
|
|
902
|
-
/*
|
|
903
|
-
UPDATE published_methods
|
|
904
|
-
SET connection_id = (
|
|
905
|
-
SELECT id FROM connections WHERE "name" = '${aiDemoDBName}'
|
|
906
|
-
)
|
|
907
|
-
WHERE name = 'askLLM';
|
|
908
|
-
*/
|
|
909
|
-
`);
|
|
910
|
-
const activeSession = await (0, exports.runDbsSql)(page, `SELECT *
|
|
911
|
-
FROM sessions
|
|
912
|
-
WHERE user_id = (SELECT id FROM users WHERE username = 'test_user')
|
|
913
|
-
AND active = true
|
|
914
|
-
ORDER BY id_num DESC
|
|
915
|
-
LIMIT 1`, {}, { returnType: "rows" });
|
|
916
|
-
if (!activeSession.length) {
|
|
917
|
-
throw new Error("No active session found for test_user");
|
|
918
|
-
}
|
|
919
|
-
await (0, exports.runDbsSql)(page, `INSERT INTO llm_credentials(provider_id, api_key, user_id)
|
|
920
|
-
VALUES('Prostgles', \${api_key} , \${user_id} )
|
|
921
|
-
`, { api_key: btoa(activeSession[0].id), user_id: activeSession[0].user_id });
|
|
922
|
-
};
|
|
923
|
-
exports.setupProstglesLLMProvider = setupProstglesLLMProvider;
|
|
924
|
-
/** Delete existing chat during local testing */
|
|
925
|
-
const deleteExistingLLMChat = async (page) => {
|
|
926
|
-
const optsToggle = page.getByTestId("LLMChatOptions.toggle");
|
|
927
|
-
if ((await optsToggle.count()) === 0) {
|
|
928
|
-
await page.getByTestId("AskLLM").click();
|
|
929
|
-
}
|
|
930
|
-
await page.getByTestId("LLMChatOptions.toggle").click();
|
|
931
|
-
await page.getByTestId("SmartForm.delete").click();
|
|
932
|
-
await page.getByTestId("SmartForm.delete.confirm").click();
|
|
933
|
-
await page.waitForTimeout(1e3);
|
|
934
|
-
};
|
|
935
|
-
exports.deleteExistingLLMChat = deleteExistingLLMChat;
|
|
936
|
-
const deleteAllWorkspaces = async (page) => {
|
|
937
|
-
const list = page.getByTestId("WorkspaceMenu.list");
|
|
938
|
-
await list.waitFor({ state: "visible", timeout: 10e3 });
|
|
939
|
-
await page.waitForTimeout(1500);
|
|
940
|
-
const listTextContent = await list.textContent();
|
|
941
|
-
if (listTextContent?.trim().toLowerCase() === "default")
|
|
942
|
-
return; // only default workspace exists
|
|
943
|
-
await page.getByTestId("WorkspaceMenuDropDown").click();
|
|
944
|
-
await page.getByTestId("WorkspaceDeleteBtn").last().click();
|
|
945
|
-
await page.getByTestId("WorkspaceDeleteBtn.Confirm").click();
|
|
946
|
-
await page.waitForTimeout(555);
|
|
947
|
-
await page.reload();
|
|
948
|
-
return (0, exports.deleteAllWorkspaces)(page);
|
|
949
|
-
};
|
|
950
|
-
exports.deleteAllWorkspaces = deleteAllWorkspaces;
|
|
951
|
-
const setOrAddWorkspace = async (page, workspaceName) => {
|
|
952
|
-
const workspaceList = await page.getByTestId("WorkspaceMenu.list");
|
|
953
|
-
await workspaceList.waitFor({ state: "visible", timeout: 10e3 });
|
|
954
|
-
await page.waitForTimeout(1500);
|
|
955
|
-
const toggleBtn = await page
|
|
956
|
-
.getByTestId("WorkspaceMenu.list")
|
|
957
|
-
.getByText(workspaceName, { exact: true });
|
|
958
|
-
if (await toggleBtn.count()) {
|
|
959
|
-
await toggleBtn.click();
|
|
960
|
-
}
|
|
961
|
-
else {
|
|
962
|
-
await page.getByTestId("WorkspaceMenuDropDown").click();
|
|
963
|
-
await page.getByTestId("WorkspaceMenuDropDown.WorkspaceAddBtn").click();
|
|
964
|
-
await page.getByLabel("New workspace name").fill(workspaceName);
|
|
965
|
-
await page.getByTestId("WorkspaceAddBtn.Create").click();
|
|
966
|
-
}
|
|
967
|
-
await page.waitForTimeout(1e3);
|
|
968
|
-
};
|
|
969
|
-
exports.setOrAddWorkspace = setOrAddWorkspace;
|
|
970
|
-
const newChat = async (page) => {
|
|
971
|
-
await page.getByTestId("AskLLMChat.NewChat").click();
|
|
972
|
-
await page.waitForTimeout(2e3);
|
|
973
|
-
};
|
|
974
|
-
exports.newChat = newChat;
|
|
975
|
-
let setupAuthCount = 0;
|
|
976
|
-
const setupMagicLinkAuth = async (page) => {
|
|
977
|
-
await page.getByTestId("EmailAuthSetup").locator("button").click();
|
|
978
|
-
await page.getByTestId("EmailAuthSetup.SignupType").click();
|
|
979
|
-
await page.locator(`[data-key="withMagicLink"]`).click();
|
|
980
|
-
await page.getByTestId("EmailSMTPAndTemplateSetup").locator("button").click();
|
|
981
|
-
await page.getByTestId("EmailSMTPSetup").locator("button").click();
|
|
982
|
-
await page.locator("input#smtp-Port").fill((465 + setupAuthCount).toString());
|
|
983
|
-
await page.locator(`[data-label="Host"] input`).fill("prostgles-test-mock");
|
|
984
|
-
await page.getByTestId("EmailSMTPAndTemplateSetup.save").click();
|
|
985
|
-
await page.waitForTimeout(1500);
|
|
986
|
-
const errNodeCount = await page.getByTestId("EmailAuthSetup.error").count();
|
|
987
|
-
await (0, test_1.expect)(errNodeCount).toBe(0);
|
|
988
|
-
setupAuthCount++;
|
|
989
|
-
};
|
|
990
|
-
exports.setupMagicLinkAuth = setupMagicLinkAuth;
|
|
991
|
-
const clickAndWait = async (btnLocator, timeout = constants_1.IS_GITHUB_WORKER ? 220_000 : 120_000) => {
|
|
992
|
-
await btnLocator.click();
|
|
993
|
-
await btnLocator.page().waitForTimeout(200);
|
|
994
|
-
await (0, test_1.expect)(btnLocator).toBeDisabled();
|
|
995
|
-
await (0, test_1.expect)(btnLocator).toBeEnabled({ timeout }); // waits until loading finishes
|
|
996
|
-
};
|
|
997
|
-
exports.clickAndWait = clickAndWait;
|
|
998
|
-
const enableMCPServers = async (page, serverNames, needsConfigSetup = false, toggleOn = true) => {
|
|
999
|
-
await page.getByTestId("LLMChatOptions.MCPTools").click({ timeout: 10e3 });
|
|
1000
|
-
for (const serverName of serverNames) {
|
|
1001
|
-
const toggleCheckbox = page
|
|
1002
|
-
.locator((0, Testing_1.getDataKey)(serverName))
|
|
1003
|
-
.getByTestId("MCPServerFooterActions.enableToggle");
|
|
1004
|
-
await toggleCheckbox.scrollIntoViewIfNeeded();
|
|
1005
|
-
await page.waitForTimeout(500);
|
|
1006
|
-
await toggleCheckbox.click();
|
|
1007
|
-
await page.waitForTimeout(500);
|
|
1008
|
-
if (!needsConfigSetup) {
|
|
1009
|
-
if (toggleOn) {
|
|
1010
|
-
await (0, test_1.expect)(toggleCheckbox).toBeChecked({ timeout: 15e3 });
|
|
1011
|
-
}
|
|
1012
|
-
else {
|
|
1013
|
-
await (0, test_1.expect)(toggleCheckbox).not.toBeChecked({ timeout: 15e3 });
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
};
|
|
1018
|
-
exports.enableMCPServers = enableMCPServers;
|
|
1019
|
-
const deletePreviousMessages = async (page) => {
|
|
1020
|
-
const firstMessage = await page.getByTestId("AskLLM.DeleteMessage").first();
|
|
1021
|
-
if (await firstMessage.count()) {
|
|
1022
|
-
await firstMessage.click();
|
|
1023
|
-
await page.locator((0, Testing_1.getDataKey)("allToBottom")).click();
|
|
1024
|
-
}
|
|
1025
|
-
};
|
|
1026
|
-
exports.deletePreviousMessages = deletePreviousMessages;
|
|
1027
|
-
const allowOnce = async (page, doClick = true) => {
|
|
1028
|
-
const allowOnceBtn = await page
|
|
1029
|
-
.getByTestId("AskLLMToolApprover.AllowOnce")
|
|
1030
|
-
.last();
|
|
1031
|
-
await allowOnceBtn.waitFor({ state: "visible", timeout: 15000 });
|
|
1032
|
-
doClick && (await allowOnceBtn.click());
|
|
1033
|
-
await page.waitForTimeout(2500);
|
|
1034
|
-
};
|
|
1035
|
-
exports.allowOnce = allowOnce;
|
|
1036
|
-
// This function is used to scroll an element into view, playwright's version of this scrollIntoViewIfNeeded() results in flaky tests
|
|
1037
|
-
async function scrollElementIntoView(locator) {
|
|
1038
|
-
await locator.evaluate((element) => {
|
|
1039
|
-
element.scrollIntoView({ block: "center" });
|
|
1040
|
-
});
|
|
1041
|
-
}
|