Files
upstream-mirror 135ffdb085
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
snapshot of https://github.com/krayin/laravel-crm.git (2.2, 2026-09-18; blobs > 131072B omitted)
2026-09-18 04:37:41 +05:00

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();
});
});
}
}