mirror of
https://github.com/n8n-io/n8n.git
synced 2025-02-02 07:01:30 -08:00
141 lines
4 KiB
TypeScript
141 lines
4 KiB
TypeScript
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<Element>) => {
|
|
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 = <TStoreDef extends () => unknown>(
|
|
useStore: TStoreDef,
|
|
): TStoreDef extends StoreDefinition<infer Id, infer State, infer Getters, infer Actions>
|
|
? Store<
|
|
Id,
|
|
State,
|
|
Record<string, never>,
|
|
{
|
|
[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<infer T> ? T : never;
|
|
}
|
|
: ReturnType<TStoreDef> => {
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
return useStore() as any;
|
|
};
|
|
|
|
export type MockedStore<T extends () => unknown> = ReturnType<typeof mockedStore<T>>;
|