Some checks failed
Admin | Playwright Tests / Admin | Playwright Tests | Shard 1 Of 6 (push) Failing after 37s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 2 Of 6 (push) Failing after 7s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 4 Of 6 (push) Failing after 7s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 6 Of 6 (push) Failing after 6s
Linting Tests / PHP 8.3 test on ubuntu-latest (push) Failing after 5s
CI / PHP 8.3 test on ubuntu-latest (push) Failing after 6s
Skills Consistency / validate-skills (push) Successful in 10s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 3 Of 6 (push) Failing after 7s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 5 Of 6 (push) Failing after 6s
135 lines
4.9 KiB
TypeScript
135 lines
4.9 KiB
TypeScript
import { Page, Locator, expect } from '@playwright/test';
|
|
import { SettingsPage } from '../SettingsPage';
|
|
import path from 'path';
|
|
import fs from 'fs';
|
|
import { parse } from 'fast-csv';
|
|
import { format } from '@fast-csv/format';
|
|
export type EntityType = 'leads' | 'products' | 'persons';
|
|
export class DataTransferPage extends SettingsPage {
|
|
readonly page: Page;
|
|
|
|
// Locators
|
|
readonly importPageUrl = 'admin/settings/data-transfer/imports';
|
|
readonly createImportLink: Locator;
|
|
readonly fileInput: Locator;
|
|
readonly processQueueCheckbox: Locator;
|
|
readonly processQueueInput: Locator;
|
|
readonly entityTypeSelect: Locator;
|
|
readonly saveImportButton: Locator;
|
|
readonly validateButton: Locator;
|
|
readonly runImportButton: Locator;
|
|
readonly importRecordsText: Locator;
|
|
readonly editIcon: Locator;
|
|
readonly deleteIcon: Locator;
|
|
readonly confirmDeleteButton: Locator;
|
|
|
|
constructor(page: Page) {
|
|
super(page);
|
|
this.page = page;
|
|
this.createImportLink = page.locator('a.primary-button');
|
|
this.fileInput = page.locator('input[name="file"]');
|
|
this.processQueueCheckbox = page.locator('label[for="process_in_queue"]');
|
|
this.processQueueInput = page.locator('input[name="process_in_queue"]');
|
|
this.entityTypeSelect = page.locator('#import-type');
|
|
this.saveImportButton = page.getByRole('button', { name: 'Save Import' });
|
|
this.validateButton = page.locator('//button[contains(.,"Validate")]');
|
|
this.runImportButton = page.getByRole('button', { name: 'Import' });
|
|
this.importRecordsText = page.getByRole('paragraph').filter({ hasText: /^leads$/ });
|
|
this.editIcon = page.locator('.icon-edit').first();
|
|
this.deleteIcon = page.locator('.icon-delete').first();
|
|
this.confirmDeleteButton = page.getByRole('button', { name: 'Agree', exact: true });
|
|
|
|
}
|
|
|
|
|
|
async createImport(csvFilePath: string, entityType: EntityType) {
|
|
|
|
await this.createImportLink.click();
|
|
await this.setInputFiles('input[name="file"]', csvFilePath);
|
|
await this.uncheckProcessQueue();
|
|
|
|
await this.entityTypeSelect.selectOption(entityType);
|
|
await this.saveImportButton.click();
|
|
|
|
await this.page.locator('//button[contains(.,"Validate")]').click();
|
|
await this.runImportButton.click();
|
|
|
|
// Wait for success record appearance
|
|
await expect(this.successMessage.first()).toBeVisible();
|
|
}
|
|
async updateImport(csvFilePath: string) {
|
|
await this.editIcon.click();
|
|
await this.setInputFiles('input[name="file"]', csvFilePath);
|
|
await this.uncheckProcessQueue();
|
|
await this.saveImportButton.click();
|
|
|
|
// Validation and import
|
|
await this.page.locator('//button[@class="primary-button place-self-start"]').click();
|
|
await expect(this.page.getByText('Your import is valid. Click')).toBeVisible();
|
|
|
|
await this.runImportButton.click();
|
|
|
|
// Wait for success message
|
|
await expect(this.page.getByText('Congratulations! Your import')).toBeVisible();
|
|
}
|
|
|
|
async deleteImport() {
|
|
|
|
await this.deleteIcon.click();
|
|
await this.confirmDeleteButton.click();
|
|
// Confirm deletion and presence of 'No Records Available.'
|
|
await expect(this.successMessage.first()).toBeVisible();
|
|
}
|
|
|
|
/**
|
|
* The import must run synchronously in every test, otherwise the records are
|
|
* only queued and the assertions race the queue worker. The switch is toggled
|
|
* through its label because the real checkbox is visually hidden, and it is
|
|
* clicked only when checked so the state stays deterministic on both the
|
|
* create form (off by default) and the edit form (reflects the saved import).
|
|
*/
|
|
async uncheckProcessQueue() {
|
|
await this.processQueueInput.waitFor({ state: 'attached' });
|
|
|
|
if (await this.processQueueInput.isChecked()) {
|
|
await this.processQueueCheckbox.click();
|
|
}
|
|
|
|
await expect(this.processQueueInput).not.toBeChecked();
|
|
}
|
|
|
|
// Utility method for setting files, with fallback to Playwright's method
|
|
async setInputFiles(selector: string, filePath: string) {
|
|
await this.page.setInputFiles(selector, filePath);
|
|
}
|
|
|
|
async updateCsv(filePath: string,column:string, newOrgId: string): Promise<void> {
|
|
return new Promise((resolve, reject) => {
|
|
const rows: any[] = [];
|
|
|
|
fs.createReadStream(filePath)
|
|
.pipe(parse({ headers: true }))
|
|
.on('error', reject)
|
|
.on('data', (row) => {
|
|
row[column] = newOrgId; // only update this field
|
|
rows.push(row);
|
|
})
|
|
.on('end', () => {
|
|
const writeStream = fs.createWriteStream(filePath);
|
|
const csvStream = format({ headers: true });
|
|
|
|
csvStream
|
|
.pipe(writeStream)
|
|
.on('finish', resolve)
|
|
.on('error', reject);
|
|
|
|
rows.forEach(row => csvStream.write(row));
|
|
csvStream.end();
|
|
});
|
|
});
|
|
}
|
|
|
|
|
|
|
|
}
|