import { ActionPanelQA, ConnectionsActionPanelControls, ConnectionsBaseQA, ConnectionsFormQA, ConnectionsS3BaseQA, ConnectionsYadocsQA, DialogCreateWorkbookEntryQa, EntryDialogQA, SharedEntriesBaseQa, } from '../../../src/shared/constants'; import {ActionPanelEntryContextMenuQa} from '../../../src/shared/constants/qa/action-panel'; import {v1 as uuidv1} from 'uuid'; import {slct, waitForCondition} from '../../utils'; import {BasePage} from '../BasePage'; import type {BasePageProps} from '../BasePage'; import type {ConsoleMessage, Request, FileChooser} from '@playwright/test'; import Revisions from '../common/Revisions'; import XLSX from '@datalens-tech/xlsx'; import {CSV_FILE, XLSX_FILE} from '../../constants/mock-data'; import os from 'os'; import path from 'path'; import fs from 'fs'; type ConnectionsPageProps = BasePageProps; type FillInputArgs = {name: string; value: string}; type FillFormInputArgs = {id: 'input'} & FillInputArgs; class ConnectionsPage extends BasePage { revisions: Revisions; private createQlChartButtonSelector = slct( ConnectionsActionPanelControls.CREATE_QL_CHART_BUTTON, ); private createDatasetButtonSelector = slct( ConnectionsActionPanelControls.CREATE_DATASET_BUTTON, ); constructor({page}: ConnectionsPageProps) { super({page}); this.revisions = new Revisions(page); } async checkIsReadonlyState() { await this.page.waitForSelector(slct(SharedEntriesBaseQa.OpenOriginalBtn)); } async createQlChart() { await this.page.click(this.createQlChartButtonSelector); } async createDataset() { await this.page.click(this.createDatasetButtonSelector); } async fillCreateConnectionInFolder({name}: {name: string}) { const textInput = this.page.locator(slct(EntryDialogQA.PathSelect)).locator('input'); // type connection name await textInput.fill(name); // create connection await this.page.locator(slct(EntryDialogQA.Apply)).click(); try { await this.page.waitForURL(() => this.page.url().includes(name)); } catch { throw new Error("Connection wasn't created"); } } async createConnectionInFolder({name = uuidv1()}: {name?: string} = {}) { // open creation dialog await this.page.locator(slct(ConnectionsBaseQA.SUBMIT_ACTION_BUTTON)).click(); await this.fillCreateConnectionInFolder({name}); } async createConnectionInWorkbookOrCollection({ name = uuidv1(), collectionId, }: {name?: string; collectionId?: string} = {}) { const formSubmit = await this.page.waitForSelector( slct(ConnectionsBaseQA.SUBMIT_ACTION_BUTTON), ); // open creation dialog await formSubmit.click(); const textInput = this.page .locator(slct(DialogCreateWorkbookEntryQa.Input)) .locator('input'); // clear input await textInput.press('Meta+A'); await textInput.press('Backspace'); // type connection name await textInput.fill(name); const dialogApplyButton = await this.page.waitForSelector( slct(DialogCreateWorkbookEntryQa.ApplyButton), ); // create connection await dialogApplyButton.click(); try { if (collectionId) { await this.page.waitForURL(() => { return this.page.url().endsWith(collectionId); }); } else { await this.page.waitForURL(() => { return this.page.url().includes(name); }); } return name; } catch { throw new Error("Connection wasn't created"); } } async checkClientValidationErrors() { let hasValidationErrors = false; const onConsoleLog = (msg: ConsoleMessage) => { if (msg.text().includes('Validation errors')) { hasValidationErrors = true; } }; this.page.on('console', onConsoleLog); const formSubmit = await this.page.waitForSelector( slct(ConnectionsBaseQA.SUBMIT_ACTION_BUTTON), ); await formSubmit.click(); await waitForCondition(async () => { return hasValidationErrors; }); this.page.off('console', onConsoleLog); } getFieldSelector(name: string) { return `conn-input-${name}`; } async fillInput({name, value}: {name: string; value: string}) { const selector = this.getFieldSelector(name); const input = await this.page.waitForSelector(slct(selector)); // focus input await input.click(); await input.type(value); } async fillForm(args: FillFormInputArgs[]) { for (const control of args) { const {id, name, value} = control; switch (id) { case 'input': { await this.fillInput({name, value}); break; } } } } async fillAndSubmitAddYadocDialog(fileUrl: string) { const fileInput = await this.page.waitForSelector( `${slct(ConnectionsYadocsQA.ADD_DOCUMENT_DIALOG_INPUT)} input`, ); await fileInput.click(); await fileInput.fill(fileUrl); const addFileDialogSubmitButton = await this.page.waitForSelector( slct(ConnectionsYadocsQA.ADD_DOCUMENT_DIALOG_SUBMIT_BUTTON), ); await addFileDialogSubmitButton.click(); } async applyS3SourceDialogAndForSourcesUpdating() { const updateFileSourceRequests: Request[] = []; this.page.on('request', (request) => { if (request.url().includes('updateFileSource')) { updateFileSourceRequests.push(request); } }); const submitButton = await this.page.waitForSelector( slct(ConnectionsS3BaseQA.S3_SOURCE_DIALOG_SUBMIT_BUTTON), ); await submitButton.click(); await Promise.all( updateFileSourceRequests.map(async (request) => { const response = await request.response(); expect(response?.status()).toBe(200); }), ); } async saveUpdatedConnection() { await this.page.locator(slct(ConnectionsBaseQA.SUBMIT_ACTION_BUTTON)).click(); } async removeConnection() { const moreButton = this.page.locator(slct(ActionPanelQA.MoreBtn)); expect(moreButton).toBeVisible(); await moreButton.click(); const menuItemRemove = this.page .locator(slct(ActionPanelEntryContextMenuQa.Menu)) .locator(slct(ActionPanelEntryContextMenuQa.Remove)); expect(menuItemRemove).toBeVisible(); await menuItemRemove.click(); const applyButton = this.page.locator(slct(EntryDialogQA.Apply)); expect(applyButton).toBeVisible(); await applyButton.click(); } async disableAutoCreateDashInBillingConnection() { const checkbox = await this.page.waitForSelector( slct(ConnectionsFormQA.AUTO_CREATE_DASH_CHECKBOX), ); await checkbox.click(); } async uploadCsvFile({ fileName = `${uuidv1()}.csv`, file = CSV_FILE, }: {fileName?: string; file?: string[][]} = {}) { // make file os.tmpdir(); const csvFile = path.join(os.tmpdir(), fileName); fs.writeFileSync(csvFile, file.map((row) => row.join(',')).join('\n')); await this.uploadS3File(csvFile); return {fileName, file}; } async uploadXlsxFile({ fileName = `${uuidv1()}.xlsx`, sheets = XLSX_FILE, }: {fileName?: string; sheets?: Record} = {}) { // make file const workbook = XLSX.utils.book_new(); for (const [sheetName, data] of Object.entries(sheets)) { const worksheet = XLSX.utils.aoa_to_sheet(data); XLSX.utils.book_append_sheet(workbook, worksheet, sheetName); } const xlsxFile = path.join(os.tmpdir(), fileName); XLSX.writeFile(workbook, xlsxFile); await this.uploadS3File(xlsxFile); return {fileName, sheets}; } private async uploadS3File(file: string) { const onFileChoose = (fileChooser: FileChooser) => { fileChooser.setFiles([file]); }; this.page.on('filechooser', onFileChoose); await this.page.click(slct(ConnectionsBaseQA.S3_UPLOAD_BUTTON)); this.page.off('filechooser', onFileChoose); } } export default ConnectionsPage;