import { within, waitFor } from '@testing-library/vue'; import userEvent from '@testing-library/user-event'; import type { ISettingsState } from '@/Interface'; import { UserManagementAuthenticationMethod } from '@/Interface'; import { defaultSettings } from './defaults'; import { APP_MODALS_ELEMENT_ID } from '@/constants'; import type { Mock } from 'vitest'; import type { Store, StoreDefinition } from 'pinia'; import type { ComputedRef } from 'vue'; /** * Retries the given assertion until it passes or the timeout is reached * * @example * await retry( * () => expect(screen.getByText('Hello')).toBeInTheDocument() * ); */ export const retry = async (assertion: () => void, { interval = 20, timeout = 1000 } = {}) => { return await new Promise((resolve, reject) => { const startTime = Date.now(); const tryAgain = () => { setTimeout(() => { try { resolve(assertion()); } catch (error) { if (Date.now() - startTime > timeout) { reject(error); } else { tryAgain(); } } }, interval); }; tryAgain(); }); }; export const waitAllPromises = async () => await new Promise((resolve) => setTimeout(resolve)); export const SETTINGS_STORE_DEFAULT_STATE: ISettingsState = { initialized: true, settings: defaultSettings, userManagement: { showSetupOnFirstLoad: false, smtpSetup: false, authenticationMethod: UserManagementAuthenticationMethod.Email, quota: defaultSettings.userManagement.quota, }, templatesEndpointHealthy: false, api: { enabled: false, latestVersion: 0, path: '/', swaggerUi: { enabled: false, }, }, ldap: { loginLabel: '', loginEnabled: false, }, saml: { loginLabel: '', loginEnabled: false, }, mfa: { enabled: false, }, saveDataErrorExecution: 'all', saveDataSuccessExecution: 'all', saveDataProgressExecution: false, saveManualExecutions: false, }; export const getDropdownItems = async (dropdownTriggerParent: HTMLElement) => { await userEvent.click(within(dropdownTriggerParent).getByRole('combobox')); const selectTrigger = dropdownTriggerParent.querySelector( '.select-trigger[aria-describedby]', ) as HTMLElement; await waitFor(() => expect(selectTrigger).toBeInTheDocument()); const selectDropdownId = selectTrigger.getAttribute('aria-describedby'); const selectDropdown = document.getElementById(selectDropdownId as string) as HTMLElement; await waitFor(() => expect(selectDropdown).toBeInTheDocument()); return selectDropdown.querySelectorAll('.el-select-dropdown__item'); }; export const getSelectedDropdownValue = async (items: NodeListOf) => { const selectedItem = Array.from(items).find((item) => item.classList.contains('selected')); expect(selectedItem).toBeInTheDocument(); return selectedItem?.querySelector('p')?.textContent?.trim(); }; /** * Create a container for teleported modals * * More info: https://test-utils.vuejs.org/guide/advanced/teleport#Mounting-the-Component * @returns {HTMLElement} appModals */ export const createAppModals = () => { const appModals = document.createElement('div'); appModals.id = APP_MODALS_ELEMENT_ID; document.body.appendChild(appModals); return appModals; }; export const cleanupAppModals = () => { document.body.innerHTML = ''; }; /** * Typescript helper for mocking pinia store actions return value * * @see https://pinia.vuejs.org/cookbook/testing.html#Mocking-the-returned-value-of-an-action */ export const mockedStore = unknown>( useStore: TStoreDef, ): TStoreDef extends StoreDefinition ? Store< Id, State, Record, { [K in keyof Actions]: Actions[K] extends (...args: infer Args) => infer ReturnT ? Mock<(...args: Args) => ReturnT> : Actions[K]; } > & { [K in keyof Getters]: Getters[K] extends ComputedRef ? T : never; } : ReturnType => { // eslint-disable-next-line @typescript-eslint/no-explicit-any return useStore() as any; }; export type MockedStore unknown> = ReturnType>;