import { UniDriver, waitFor } from '@wix/wix-ui-test-utils/unidriver'; import { baseUniDriverFactory } from '../../unidriver'; import { CounterBadgeUniDriver, CustomModalLayoutUniDriver, DropdownUniDriver, InputUniDriver, MessageModalLayoutUniDriver, ModalUniDriver, TextUniDriver, } from '@wix/design-system/dist/testkit/unidriver'; export function ImportModalUniDriver(base: UniDriver, body: UniDriver) { const modalBase = () => body.$('.portal-import-modal'); const modalLayoutBase = () => body.$('[data-hook="import-modal-layout"]'); const footerBase = () => modalLayoutBase().$('[data-hook="import-modal-footer-text"]'); const getModal = () => ModalUniDriver(modalBase(), modalBase()); const getModalLayout = () => CustomModalLayoutUniDriver(modalLayoutBase(), body); const getFooterText = async () => (await TextUniDriver(footerBase(), body)).getText(); const footerExists = () => footerBase().exists(); const fileInputBase = () => modalLayoutBase().$('[data-hook="import-file-input"]'); const configurationStepBase = () => modalLayoutBase().$('[data-hook="import-mapping-step"]'); const summaryStepBase = () => modalLayoutBase().$('[data-hook="import-summary-step"]'); const progressLabelBase = () => modalLayoutBase().$('[data-hook="import-progress-label"]'); return { wait: (timeout?: number) => base.wait(timeout), ...baseUniDriverFactory(base), getModal, getModalLayout, waitModalClosed: (timeout?: number) => waitFor(async () => !(await getModalLayout().exists()), timeout), clickPrimaryAction: async () => (await getModalLayout().getPrimaryButtonDriver()).click(), getPrimaryActionText: async () => (await getModalLayout().getPrimaryButtonDriver()).getButtonTextContent(), isPrimaryButtonDisabled: async () => (await getModalLayout().getPrimaryButtonDriver()).isButtonDisabled(), getSecondaryButtonText: async () => ( await getModalLayout().getSecondaryButtonDriver() ).getButtonTextContent(), clickSecondaryAction: async () => (await getModalLayout().getSecondaryButtonDriver()).click(), clickCloseButton: () => getModalLayout().clickCloseButton(), getModalTitle: () => getModalLayout().getTitleText(), getSubtitleText: () => getModalLayout().getSubtitleText(), getFooterText, footerExists, isUploadStepVisible: () => fileInputBase().exists(), isConfigurationStepVisible: () => configurationStepBase().exists(), isSummaryStepVisible: () => summaryStepBase().exists(), // Summary step count rows (created / updated / failed). Each row's text is // the translated count line; `*Exists` reflects whether that row rendered // (a count row is shown only when its count is > 0). summaryCreatedExists: () => summaryStepBase().$('[data-hook="import-summary-created"]').exists(), getSummaryCreatedText: () => summaryStepBase().$('[data-hook="import-summary-created"]').text(), summaryUpdatedExists: () => summaryStepBase().$('[data-hook="import-summary-updated"]').exists(), getSummaryUpdatedText: () => summaryStepBase().$('[data-hook="import-summary-updated"]').text(), summaryFailedExists: () => summaryStepBase().$('[data-hook="import-summary-failed"]').exists(), getSummaryFailedText: () => summaryStepBase().$('[data-hook="import-summary-failed"]').text(), /** Simulates selecting a file in the upload step */ uploadFile: async (file: File) => { const nativeInput: HTMLInputElement = await fileInputBase() .$('input[type="file"]') .getNative(); Object.defineProperty(nativeInput, 'files', { value: [file] }); nativeInput.dispatchEvent(new Event('change', { bubbles: true })); }, noRowsWarningExists: () => modalLayoutBase().$('[data-hook="import-no-rows-warning"]').exists(), getProgressLabel: () => progressLabelBase().text(), progressLabelExists: () => progressLabelBase().exists(), getErrorMessageText: () => modalLayoutBase().$('[data-hook="import-error-message"]').text(), errorMessageExists: () => modalLayoutBase().$('[data-hook="import-error-message"]').exists(), // Inline wrap style on the error message's container — asserts a long, // unbroken message is forced to wrap inside the modal instead of overflowing. getErrorMessageWrapStyle: async () => { const native: HTMLElement = await modalLayoutBase() .$('[data-hook="import-error-message-wrap"]') .getNative(); return { overflowWrap: native.style.overflowWrap, wordBreak: native.style.wordBreak, }; }, /** Get the CounterBadge driver for the columns found counter */ getColumnsFoundCounter: () => CounterBadgeUniDriver( modalLayoutBase().$('[data-hook="import-columns-found-counter"]'), body, ), /** Text of the "new field" helper line under a column's mapping dropdown */ getNewFieldHelperText: (header: string) => modalLayoutBase() .$(`[data-hook="import-new-field-helper-${header}"]`) .text(), newFieldHelperExists: (header: string) => modalLayoutBase() .$(`[data-hook="import-new-field-helper-${header}"]`) .exists(), /** Get the Dropdown driver for a specific CSV header mapping */ getMappingDropdown: (header: string) => DropdownUniDriver( modalLayoutBase().$(`[data-hook="import-mapping-${header}"]`), body, ), /** * CSV headers in the order their mapping rows are rendered (ID row first). * Reads the per-row column-title cells in DOM order — `.text()` on the * multi-element query returns their text as an ordered array. */ getMappingHeadersInOrder: () => modalLayoutBase().$$('[data-hook="import-column-title"]').text(), /** Whether the "When items share the same ID" sentence + action are shown */ idCollisionControlExists: () => modalLayoutBase().$('[data-hook="import-id-collision-action"]').exists(), /** Current label of the id-collision inline action (reflects the choice) */ getIdCollisionActionText: () => modalLayoutBase().$('[data-hook="import-id-collision-action"]').text(), /** Open the id-collision popover menu */ openIdCollisionMenu: () => modalLayoutBase().$('[data-hook="import-id-collision-action"]').click(), // The popover menu renders at `window` (appendTo), so its items live on // `body`, not under the modal layout. clickIdCollisionUpdate: () => body.$('[data-hook="import-id-collision-update"]').click(), clickIdCollisionSkip: () => body.$('[data-hook="import-id-collision-skip"]').click(), /** Whether the "Edit field" link under a column's new-field mapping exists */ editFieldLinkExists: (header: string) => modalLayoutBase().$(`[data-hook="import-edit-field-${header}"]`).exists(), /** Click the "Edit field" link to open the field editor for a column */ clickEditField: (header: string) => modalLayoutBase().$(`[data-hook="import-edit-field-${header}"]`).click(), // The mapping dropdown's popover appends to `window`, so its "+ Create New // Field" footer renders on `body`, not under the modal layout. /** Whether the dropdown's "+ Create New Field" footer is shown for a column */ createFieldFooterExists: (header: string) => body.$(`[data-hook="import-create-field-${header}"]`).exists(), /** Click the "+ Create New Field" dropdown footer for a column */ clickCreateField: (header: string) => body.$(`[data-hook="import-create-field-${header}"]`).click(), /** Whether the CMS field-editor modal is open */ fieldEditorIsOpen: () => body.$('[data-hook="field-editor-modal"]').exists(), /** Field-editor modal layout driver (Save/Cancel, title, ...) */ getFieldEditorModal: () => CustomModalLayoutUniDriver( body.$('[data-hook="field-editor-modal"]'), body, ), /** Field-editor "Field name" input driver */ getFieldEditorNameInput: () => InputUniDriver(body.$('[data-hook="cms-field-name-input"]'), body), /** Confirm (Save) the field editor */ confirmFieldEditor: async () => ( await CustomModalLayoutUniDriver( body.$('[data-hook="field-editor-modal"]'), body, ).getPrimaryButtonDriver() ).click(), /** Get the discard changes confirmation modal driver */ getDiscardChangesModal: () => MessageModalLayoutUniDriver( body.$('[data-hook="import-discard-changes-modal"]'), body, ), }; } export default ImportModalUniDriver;