mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
test(editor): SSO tests (#5946)
* test(editor): SSO tests * test(editor): move store tests to __tests__ folder * test(editor): move tests in a different PR * test(editor): add SSO tests * test(editor): add SSO settings page tests * test(editor): add SSO onboarding page base test * test(editor): add SSO onboarding page test * test(editor): fix router spy
This commit is contained in:
parent
1a8a9f8ddb
commit
bc1db5e16a
|
@ -14,8 +14,7 @@ import { showMessage } from '@/mixins/showMessage';
|
||||||
import { i18nInstance } from '@/plugins/i18n';
|
import { i18nInstance } from '@/plugins/i18n';
|
||||||
import type { IWorkflowShortResponse } from '@/Interface';
|
import type { IWorkflowShortResponse } from '@/Interface';
|
||||||
import type { IExecutionsSummary } from 'n8n-workflow';
|
import type { IExecutionsSummary } from 'n8n-workflow';
|
||||||
|
import { waitAllPromises } from '@/utils/testUtils';
|
||||||
const waitAllPromises = () => new Promise((resolve) => setTimeout(resolve));
|
|
||||||
|
|
||||||
const workflowDataFactory = (): IWorkflowShortResponse => ({
|
const workflowDataFactory = (): IWorkflowShortResponse => ({
|
||||||
createdAt: faker.date.past().toDateString(),
|
createdAt: faker.date.past().toDateString(),
|
||||||
|
|
59
packages/editor-ui/src/components/__tests__/SSOLogin.test.ts
Normal file
59
packages/editor-ui/src/components/__tests__/SSOLogin.test.ts
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
import { PiniaVuePlugin } from 'pinia';
|
||||||
|
import { render } from '@testing-library/vue';
|
||||||
|
import { createTestingPinia } from '@pinia/testing';
|
||||||
|
import { merge } from 'lodash-es';
|
||||||
|
import SSOLogin from '@/components/SSOLogin.vue';
|
||||||
|
import { STORES } from '@/constants';
|
||||||
|
import { useSSOStore } from '@/stores/sso';
|
||||||
|
import { SETTINGS_STORE_DEFAULT_STATE } from '@/utils/testUtils';
|
||||||
|
import { afterEach } from 'vitest';
|
||||||
|
|
||||||
|
let pinia: ReturnType<typeof createTestingPinia>;
|
||||||
|
let ssoStore: ReturnType<typeof useSSOStore>;
|
||||||
|
|
||||||
|
const renderComponent = (renderOptions: Parameters<typeof render>[1] = {}) =>
|
||||||
|
render(
|
||||||
|
SSOLogin,
|
||||||
|
merge(
|
||||||
|
{
|
||||||
|
pinia,
|
||||||
|
stubs: {
|
||||||
|
'n8n-button': {
|
||||||
|
template: '<button data-testid="sso-button"></button>',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
renderOptions,
|
||||||
|
),
|
||||||
|
(vue) => {
|
||||||
|
vue.use(PiniaVuePlugin);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('SSOLogin', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
pinia = createTestingPinia({
|
||||||
|
initialState: {
|
||||||
|
[STORES.SETTINGS]: {
|
||||||
|
settings: merge({}, SETTINGS_STORE_DEFAULT_STATE.settings),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
ssoStore = useSSOStore();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not render button if conditions are not met', () => {
|
||||||
|
const { queryByRole } = renderComponent();
|
||||||
|
expect(queryByRole('button')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render button if the store returns true for the conditions', () => {
|
||||||
|
vi.spyOn(ssoStore, 'showSsoLoginButton', 'get').mockReturnValue(true);
|
||||||
|
const { queryByRole } = renderComponent();
|
||||||
|
expect(queryByRole('button')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
48
packages/editor-ui/src/stores/__tests__/sso.test.ts
Normal file
48
packages/editor-ui/src/stores/__tests__/sso.test.ts
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import { createPinia, setActivePinia } from 'pinia';
|
||||||
|
import { useSettingsStore } from '@/stores/settings';
|
||||||
|
import { useSSOStore } from '@/stores/sso';
|
||||||
|
import { merge } from 'lodash-es';
|
||||||
|
import { IN8nUISettings } from '@/Interface';
|
||||||
|
import { SETTINGS_STORE_DEFAULT_STATE } from '@/utils/testUtils';
|
||||||
|
|
||||||
|
let ssoStore: ReturnType<typeof useSSOStore>;
|
||||||
|
let settingsStore: ReturnType<typeof useSettingsStore>;
|
||||||
|
|
||||||
|
const DEFAULT_SETTINGS: IN8nUISettings = SETTINGS_STORE_DEFAULT_STATE.settings;
|
||||||
|
|
||||||
|
describe('SSO store', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
setActivePinia(createPinia());
|
||||||
|
ssoStore = useSSOStore();
|
||||||
|
settingsStore = useSettingsStore();
|
||||||
|
});
|
||||||
|
|
||||||
|
test.each([
|
||||||
|
['saml', true, true, true],
|
||||||
|
['saml', false, true, false],
|
||||||
|
['saml', false, false, false],
|
||||||
|
['saml', true, false, false],
|
||||||
|
['email', true, true, false],
|
||||||
|
])(
|
||||||
|
'should check SSO login button availability when authenticationMethod is %s and enterprise feature is %s and sso login is set to %s',
|
||||||
|
(authenticationMethod, saml, loginEnabled, expectation) => {
|
||||||
|
settingsStore.setSettings(
|
||||||
|
merge({}, DEFAULT_SETTINGS, {
|
||||||
|
userManagement: {
|
||||||
|
authenticationMethod,
|
||||||
|
},
|
||||||
|
enterprise: {
|
||||||
|
saml,
|
||||||
|
},
|
||||||
|
sso: {
|
||||||
|
saml: {
|
||||||
|
loginEnabled,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(ssoStore.showSsoLoginButton).toBe(expectation);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
|
@ -75,6 +75,7 @@ export const useSSOStore = defineStore('sso', () => {
|
||||||
setLoading,
|
setLoading,
|
||||||
isSamlLoginEnabled,
|
isSamlLoginEnabled,
|
||||||
isEnterpriseSamlEnabled,
|
isEnterpriseSamlEnabled,
|
||||||
|
isDefaultAuthenticationSaml,
|
||||||
showSsoLoginButton,
|
showSsoLoginButton,
|
||||||
getSSORedirectUrl,
|
getSSORedirectUrl,
|
||||||
getSamlMetadata,
|
getSamlMetadata,
|
||||||
|
|
|
@ -1,76 +1,15 @@
|
||||||
import { beforeAll } from 'vitest';
|
import { beforeAll } from 'vitest';
|
||||||
import { setActivePinia, createPinia } from 'pinia';
|
import { setActivePinia, createPinia } from 'pinia';
|
||||||
|
import { merge } from 'lodash-es';
|
||||||
import { isAuthorized } from '@/utils';
|
import { isAuthorized } from '@/utils';
|
||||||
import { useSettingsStore } from '@/stores/settings';
|
import { useSettingsStore } from '@/stores/settings';
|
||||||
import { useSSOStore } from '@/stores/sso';
|
import { useSSOStore } from '@/stores/sso';
|
||||||
import { IN8nUISettings, IUser, UserManagementAuthenticationMethod } from '@/Interface';
|
import { IN8nUISettings, IUser } from '@/Interface';
|
||||||
import { routes } from '@/router';
|
import { routes } from '@/router';
|
||||||
import { VIEWS } from '@/constants';
|
import { VIEWS } from '@/constants';
|
||||||
|
import { SETTINGS_STORE_DEFAULT_STATE } from '@/utils/testUtils';
|
||||||
|
|
||||||
const DEFAULT_SETTINGS: IN8nUISettings = {
|
const DEFAULT_SETTINGS: IN8nUISettings = SETTINGS_STORE_DEFAULT_STATE.settings;
|
||||||
allowedModules: {},
|
|
||||||
communityNodesEnabled: false,
|
|
||||||
defaultLocale: '',
|
|
||||||
endpointWebhook: '',
|
|
||||||
endpointWebhookTest: '',
|
|
||||||
enterprise: {
|
|
||||||
advancedExecutionFilters: false,
|
|
||||||
sharing: false,
|
|
||||||
ldap: false,
|
|
||||||
saml: false,
|
|
||||||
logStreaming: false,
|
|
||||||
},
|
|
||||||
executionMode: '',
|
|
||||||
executionTimeout: 0,
|
|
||||||
hideUsagePage: false,
|
|
||||||
hiringBannerEnabled: false,
|
|
||||||
instanceId: '',
|
|
||||||
isNpmAvailable: false,
|
|
||||||
license: { environment: 'production' },
|
|
||||||
logLevel: 'info',
|
|
||||||
maxExecutionTimeout: 0,
|
|
||||||
oauthCallbackUrls: { oauth1: '', oauth2: '' },
|
|
||||||
onboardingCallPromptEnabled: false,
|
|
||||||
personalizationSurveyEnabled: false,
|
|
||||||
posthog: {
|
|
||||||
apiHost: '',
|
|
||||||
apiKey: '',
|
|
||||||
autocapture: false,
|
|
||||||
debug: false,
|
|
||||||
disableSessionRecording: false,
|
|
||||||
enabled: false,
|
|
||||||
},
|
|
||||||
publicApi: { enabled: false, latestVersion: 0, path: '', swaggerUi: { enabled: false } },
|
|
||||||
pushBackend: 'sse',
|
|
||||||
saveDataErrorExecution: '',
|
|
||||||
saveDataSuccessExecution: '',
|
|
||||||
saveManualExecutions: false,
|
|
||||||
sso: {
|
|
||||||
ldap: { loginEnabled: false, loginLabel: '' },
|
|
||||||
saml: { loginEnabled: false, loginLabel: '' },
|
|
||||||
},
|
|
||||||
telemetry: { enabled: false },
|
|
||||||
templates: { enabled: false, host: '' },
|
|
||||||
timezone: '',
|
|
||||||
urlBaseEditor: '',
|
|
||||||
urlBaseWebhook: '',
|
|
||||||
userManagement: {
|
|
||||||
enabled: false,
|
|
||||||
smtpSetup: false,
|
|
||||||
authenticationMethod: UserManagementAuthenticationMethod.Email,
|
|
||||||
},
|
|
||||||
versionCli: '',
|
|
||||||
versionNotifications: {
|
|
||||||
enabled: false,
|
|
||||||
endpoint: '',
|
|
||||||
infoUrl: '',
|
|
||||||
},
|
|
||||||
workflowCallerPolicyDefaultOption: 'any',
|
|
||||||
workflowTagsDisabled: false,
|
|
||||||
deployment: {
|
|
||||||
type: 'default',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const DEFAULT_USER: IUser = {
|
const DEFAULT_USER: IUser = {
|
||||||
id: '1',
|
id: '1',
|
||||||
|
@ -101,23 +40,18 @@ describe('userUtils', () => {
|
||||||
.find((route) => route.path.startsWith('/settings'))
|
.find((route) => route.path.startsWith('/settings'))
|
||||||
?.children?.find((route) => route.name === VIEWS.SSO_SETTINGS)?.meta?.permissions;
|
?.children?.find((route) => route.name === VIEWS.SSO_SETTINGS)?.meta?.permissions;
|
||||||
|
|
||||||
const user: IUser = {
|
const user: IUser = merge({}, DEFAULT_USER, {
|
||||||
...DEFAULT_USER,
|
|
||||||
isDefaultUser: false,
|
isDefaultUser: false,
|
||||||
isOwner: true,
|
isOwner: true,
|
||||||
globalRole: {
|
globalRole: {
|
||||||
...DEFAULT_USER.globalRole,
|
|
||||||
id: '1',
|
id: '1',
|
||||||
name: 'owner',
|
name: 'owner',
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
},
|
},
|
||||||
};
|
|
||||||
|
|
||||||
settingsStore.setSettings({
|
|
||||||
...DEFAULT_SETTINGS,
|
|
||||||
enterprise: { ...DEFAULT_SETTINGS.enterprise, saml: true },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
settingsStore.setSettings(merge({}, DEFAULT_SETTINGS, { enterprise: { saml: true } }));
|
||||||
|
|
||||||
expect(isAuthorized(ssoSettingsPermissions, user)).toBe(true);
|
expect(isAuthorized(ssoSettingsPermissions, user)).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
103
packages/editor-ui/src/utils/testUtils.ts
Normal file
103
packages/editor-ui/src/utils/testUtils.ts
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
import { ISettingsState, UserManagementAuthenticationMethod } from '@/Interface';
|
||||||
|
|
||||||
|
export const waitAllPromises = () => new Promise((resolve) => setTimeout(resolve));
|
||||||
|
|
||||||
|
export const SETTINGS_STORE_DEFAULT_STATE: ISettingsState = {
|
||||||
|
settings: {
|
||||||
|
allowedModules: {},
|
||||||
|
communityNodesEnabled: false,
|
||||||
|
defaultLocale: '',
|
||||||
|
endpointWebhook: '',
|
||||||
|
endpointWebhookTest: '',
|
||||||
|
enterprise: {
|
||||||
|
advancedExecutionFilters: false,
|
||||||
|
sharing: false,
|
||||||
|
ldap: false,
|
||||||
|
saml: false,
|
||||||
|
logStreaming: false,
|
||||||
|
},
|
||||||
|
executionMode: '',
|
||||||
|
executionTimeout: 0,
|
||||||
|
hideUsagePage: false,
|
||||||
|
hiringBannerEnabled: false,
|
||||||
|
instanceId: '',
|
||||||
|
isNpmAvailable: false,
|
||||||
|
license: { environment: 'production' },
|
||||||
|
logLevel: 'info',
|
||||||
|
maxExecutionTimeout: 0,
|
||||||
|
oauthCallbackUrls: { oauth1: '', oauth2: '' },
|
||||||
|
onboardingCallPromptEnabled: false,
|
||||||
|
personalizationSurveyEnabled: false,
|
||||||
|
posthog: {
|
||||||
|
apiHost: '',
|
||||||
|
apiKey: '',
|
||||||
|
autocapture: false,
|
||||||
|
debug: false,
|
||||||
|
disableSessionRecording: false,
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
publicApi: { enabled: false, latestVersion: 0, path: '', swaggerUi: { enabled: false } },
|
||||||
|
pushBackend: 'sse',
|
||||||
|
saveDataErrorExecution: '',
|
||||||
|
saveDataSuccessExecution: '',
|
||||||
|
saveManualExecutions: false,
|
||||||
|
sso: {
|
||||||
|
ldap: { loginEnabled: false, loginLabel: '' },
|
||||||
|
saml: { loginEnabled: false, loginLabel: '' },
|
||||||
|
},
|
||||||
|
telemetry: { enabled: false },
|
||||||
|
templates: { enabled: false, host: '' },
|
||||||
|
timezone: '',
|
||||||
|
urlBaseEditor: '',
|
||||||
|
urlBaseWebhook: '',
|
||||||
|
userManagement: {
|
||||||
|
enabled: false,
|
||||||
|
smtpSetup: false,
|
||||||
|
authenticationMethod: UserManagementAuthenticationMethod.Email,
|
||||||
|
},
|
||||||
|
versionCli: '',
|
||||||
|
versionNotifications: {
|
||||||
|
enabled: false,
|
||||||
|
endpoint: '',
|
||||||
|
infoUrl: '',
|
||||||
|
},
|
||||||
|
workflowCallerPolicyDefaultOption: 'any',
|
||||||
|
workflowTagsDisabled: false,
|
||||||
|
deployment: {
|
||||||
|
type: 'default',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
promptsData: {
|
||||||
|
message: '',
|
||||||
|
title: '',
|
||||||
|
showContactPrompt: false,
|
||||||
|
showValueSurvey: false,
|
||||||
|
},
|
||||||
|
userManagement: {
|
||||||
|
enabled: false,
|
||||||
|
showSetupOnFirstLoad: false,
|
||||||
|
smtpSetup: false,
|
||||||
|
authenticationMethod: UserManagementAuthenticationMethod.Email,
|
||||||
|
},
|
||||||
|
templatesEndpointHealthy: false,
|
||||||
|
api: {
|
||||||
|
enabled: false,
|
||||||
|
latestVersion: 0,
|
||||||
|
path: '/',
|
||||||
|
swaggerUi: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ldap: {
|
||||||
|
loginLabel: '',
|
||||||
|
loginEnabled: false,
|
||||||
|
},
|
||||||
|
saml: {
|
||||||
|
loginLabel: '',
|
||||||
|
loginEnabled: false,
|
||||||
|
},
|
||||||
|
onboardingCallPromptEnabled: false,
|
||||||
|
saveDataErrorExecution: 'all',
|
||||||
|
saveDataSuccessExecution: 'all',
|
||||||
|
saveManualExecutions: false,
|
||||||
|
};
|
|
@ -112,7 +112,7 @@ onBeforeMount(async () => {
|
||||||
</template>
|
</template>
|
||||||
</i18n>
|
</i18n>
|
||||||
</n8n-info-tip>
|
</n8n-info-tip>
|
||||||
<div v-if="ssoStore.isEnterpriseSamlEnabled">
|
<div v-if="ssoStore.isEnterpriseSamlEnabled" data-testid="sso-content-licensed">
|
||||||
<div :class="$style.group">
|
<div :class="$style.group">
|
||||||
<label>{{ locale.baseText('settings.sso.settings.redirectUrl.label') }}</label>
|
<label>{{ locale.baseText('settings.sso.settings.redirectUrl.label') }}</label>
|
||||||
<CopyInput
|
<CopyInput
|
||||||
|
@ -135,20 +135,26 @@ onBeforeMount(async () => {
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.group">
|
<div :class="$style.group">
|
||||||
<label>{{ locale.baseText('settings.sso.settings.ips.label') }}</label>
|
<label>{{ locale.baseText('settings.sso.settings.ips.label') }}</label>
|
||||||
<n8n-input v-model="metadata" type="textarea" />
|
<n8n-input v-model="metadata" type="textarea" name="metadata" />
|
||||||
<small>{{ locale.baseText('settings.sso.settings.ips.help') }}</small>
|
<small>{{ locale.baseText('settings.sso.settings.ips.help') }}</small>
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.buttons">
|
<div :class="$style.buttons">
|
||||||
<n8n-button :disabled="!ssoSettingsSaved" type="tertiary" @click="onTest">
|
<n8n-button
|
||||||
|
:disabled="!ssoSettingsSaved"
|
||||||
|
type="tertiary"
|
||||||
|
@click="onTest"
|
||||||
|
data-testid="sso-test"
|
||||||
|
>
|
||||||
{{ locale.baseText('settings.sso.settings.test') }}
|
{{ locale.baseText('settings.sso.settings.test') }}
|
||||||
</n8n-button>
|
</n8n-button>
|
||||||
<n8n-button :disabled="!metadata" @click="onSave">
|
<n8n-button :disabled="!metadata" @click="onSave" data-testid="sso-save">
|
||||||
{{ locale.baseText('settings.sso.settings.save') }}
|
{{ locale.baseText('settings.sso.settings.save') }}
|
||||||
</n8n-button>
|
</n8n-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<n8n-action-box
|
<n8n-action-box
|
||||||
v-else
|
v-else
|
||||||
|
data-testid="sso-content-unlicensed"
|
||||||
:class="$style.actionBox"
|
:class="$style.actionBox"
|
||||||
:description="locale.baseText('settings.sso.actionBox.description')"
|
:description="locale.baseText('settings.sso.actionBox.description')"
|
||||||
:buttonText="locale.baseText('settings.sso.actionBox.buttonText')"
|
:buttonText="locale.baseText('settings.sso.actionBox.buttonText')"
|
||||||
|
|
49
packages/editor-ui/src/views/__tests__/AuthView.test.ts
Normal file
49
packages/editor-ui/src/views/__tests__/AuthView.test.ts
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
import { PiniaVuePlugin } from 'pinia';
|
||||||
|
import { render } from '@testing-library/vue';
|
||||||
|
import { createTestingPinia } from '@pinia/testing';
|
||||||
|
import { merge } from 'lodash-es';
|
||||||
|
import AuthView from '@/views/AuthView.vue';
|
||||||
|
|
||||||
|
const renderComponent = (renderOptions: Parameters<typeof render>[1] = {}) =>
|
||||||
|
render(
|
||||||
|
AuthView,
|
||||||
|
merge(
|
||||||
|
{
|
||||||
|
pinia: createTestingPinia(),
|
||||||
|
stubs: {
|
||||||
|
SSOLogin: {
|
||||||
|
template: '<div data-testid="sso-login"></div>',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
renderOptions,
|
||||||
|
),
|
||||||
|
(vue) => {
|
||||||
|
vue.use(PiniaVuePlugin);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('AuthView', () => {
|
||||||
|
it('should render with subtitle', () => {
|
||||||
|
const { getByText } = renderComponent({
|
||||||
|
props: {
|
||||||
|
subtitle: 'Some text',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(getByText('Some text')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render without SSO component', () => {
|
||||||
|
const { queryByTestId } = renderComponent();
|
||||||
|
expect(queryByTestId('sso-login')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render with SSO component', () => {
|
||||||
|
const { getByTestId } = renderComponent({
|
||||||
|
props: {
|
||||||
|
withSso: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(getByTestId('sso-login')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,82 @@
|
||||||
|
import { PiniaVuePlugin } from 'pinia';
|
||||||
|
import { render } from '@testing-library/vue';
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
|
import { useRouter } from 'vue-router/composables';
|
||||||
|
import { createTestingPinia } from '@pinia/testing';
|
||||||
|
import { merge } from 'lodash-es';
|
||||||
|
import SamlOnboarding from '@/views/SamlOnboarding.vue';
|
||||||
|
import { useSSOStore } from '@/stores/sso';
|
||||||
|
import { STORES } from '@/constants';
|
||||||
|
import { SETTINGS_STORE_DEFAULT_STATE, waitAllPromises } from '@/utils/testUtils';
|
||||||
|
import { i18nInstance } from '@/plugins/i18n';
|
||||||
|
|
||||||
|
vi.mock('vue-router/composables', () => {
|
||||||
|
const push = vi.fn();
|
||||||
|
return {
|
||||||
|
useRouter: () => ({
|
||||||
|
push,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
let pinia: ReturnType<typeof createTestingPinia>;
|
||||||
|
let ssoStore: ReturnType<typeof useSSOStore>;
|
||||||
|
let router: ReturnType<typeof useRouter>;
|
||||||
|
|
||||||
|
const renderComponent = (renderOptions: Parameters<typeof render>[1] = {}) =>
|
||||||
|
render(
|
||||||
|
SamlOnboarding,
|
||||||
|
merge(
|
||||||
|
{
|
||||||
|
pinia,
|
||||||
|
i18n: i18nInstance,
|
||||||
|
},
|
||||||
|
renderOptions,
|
||||||
|
),
|
||||||
|
(vue) => {
|
||||||
|
vue.use(PiniaVuePlugin);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('SamlOnboarding', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
pinia = createTestingPinia({
|
||||||
|
initialState: {
|
||||||
|
[STORES.SETTINGS]: {
|
||||||
|
settings: merge({}, SETTINGS_STORE_DEFAULT_STATE.settings),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
ssoStore = useSSOStore(pinia);
|
||||||
|
router = useRouter();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should submit filled in form only and redirect', async () => {
|
||||||
|
vi.spyOn(ssoStore, 'updateUser').mockResolvedValue({
|
||||||
|
id: '1',
|
||||||
|
isPending: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { getByRole, getAllByRole } = renderComponent();
|
||||||
|
|
||||||
|
const inputs = getAllByRole('textbox');
|
||||||
|
const submit = getByRole('button');
|
||||||
|
|
||||||
|
await userEvent.click(submit);
|
||||||
|
await waitAllPromises();
|
||||||
|
|
||||||
|
expect(ssoStore.updateUser).not.toHaveBeenCalled();
|
||||||
|
expect(router.push).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
await userEvent.type(inputs[0], 'test');
|
||||||
|
await userEvent.type(inputs[1], 'test');
|
||||||
|
await userEvent.click(submit);
|
||||||
|
|
||||||
|
expect(ssoStore.updateUser).toHaveBeenCalled();
|
||||||
|
expect(router.push).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
115
packages/editor-ui/src/views/__tests__/SettingsSso.test.ts
Normal file
115
packages/editor-ui/src/views/__tests__/SettingsSso.test.ts
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
import { PiniaVuePlugin } from 'pinia';
|
||||||
|
import { render } from '@testing-library/vue';
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
|
import { createTestingPinia } from '@pinia/testing';
|
||||||
|
import { merge } from 'lodash-es';
|
||||||
|
import { faker } from '@faker-js/faker';
|
||||||
|
import SettingsSso from '@/views/SettingsSso.vue';
|
||||||
|
import { useSSOStore } from '@/stores/sso';
|
||||||
|
import { STORES } from '@/constants';
|
||||||
|
import { SETTINGS_STORE_DEFAULT_STATE, waitAllPromises } from '@/utils/testUtils';
|
||||||
|
import { i18nInstance } from '@/plugins/i18n';
|
||||||
|
import { SamlPreferences, SamlPreferencesExtractedData } from '@/Interface';
|
||||||
|
|
||||||
|
let pinia: ReturnType<typeof createTestingPinia>;
|
||||||
|
let ssoStore: ReturnType<typeof useSSOStore>;
|
||||||
|
|
||||||
|
const samlConfig: SamlPreferences & SamlPreferencesExtractedData = {
|
||||||
|
metadata: '<?xml version="1.0"?>',
|
||||||
|
entityID: faker.internet.url(),
|
||||||
|
returnUrl: faker.internet.url(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderComponent = (renderOptions: Parameters<typeof render>[1] = {}) =>
|
||||||
|
render(
|
||||||
|
SettingsSso,
|
||||||
|
merge(
|
||||||
|
{
|
||||||
|
pinia,
|
||||||
|
i18n: i18nInstance,
|
||||||
|
},
|
||||||
|
renderOptions,
|
||||||
|
),
|
||||||
|
(vue) => {
|
||||||
|
vue.use(PiniaVuePlugin);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('SettingsSso', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
pinia = createTestingPinia({
|
||||||
|
initialState: {
|
||||||
|
[STORES.SETTINGS]: {
|
||||||
|
settings: merge({}, SETTINGS_STORE_DEFAULT_STATE.settings),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
ssoStore = useSSOStore(pinia);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render paywall state when there is no license', () => {
|
||||||
|
const { getByTestId, queryByTestId, queryByRole } = renderComponent();
|
||||||
|
|
||||||
|
expect(queryByRole('checkbox')).not.toBeInTheDocument();
|
||||||
|
expect(queryByTestId('sso-content-licensed')).not.toBeInTheDocument();
|
||||||
|
expect(getByTestId('sso-content-unlicensed')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render licensed content', () => {
|
||||||
|
vi.spyOn(ssoStore, 'isEnterpriseSamlEnabled', 'get').mockReturnValue(true);
|
||||||
|
|
||||||
|
const { getByTestId, queryByTestId, getByRole } = renderComponent();
|
||||||
|
|
||||||
|
expect(getByRole('checkbox')).toBeInTheDocument();
|
||||||
|
expect(getByTestId('sso-content-licensed')).toBeInTheDocument();
|
||||||
|
expect(queryByTestId('sso-content-unlicensed')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should enable activation checkbox and test button if data is already saved', async () => {
|
||||||
|
vi.spyOn(ssoStore, 'isEnterpriseSamlEnabled', 'get').mockReturnValue(true);
|
||||||
|
vi.spyOn(ssoStore, 'getSamlConfig').mockResolvedValue(samlConfig);
|
||||||
|
|
||||||
|
const { getByRole, getByTestId } = renderComponent();
|
||||||
|
await waitAllPromises();
|
||||||
|
|
||||||
|
expect(getByRole('checkbox')).toBeEnabled();
|
||||||
|
expect(getByTestId('sso-test')).toBeEnabled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should enable activation checkbox after data is saved', async () => {
|
||||||
|
vi.spyOn(ssoStore, 'isEnterpriseSamlEnabled', 'get').mockReturnValue(true);
|
||||||
|
|
||||||
|
const { getByRole, getAllByRole, getByTestId } = renderComponent();
|
||||||
|
const checkbox = getByRole('checkbox');
|
||||||
|
const btnSave = getByTestId('sso-save');
|
||||||
|
const btnTest = getByTestId('sso-test');
|
||||||
|
|
||||||
|
expect(checkbox).toBeDisabled();
|
||||||
|
[btnSave, btnTest].forEach((el) => {
|
||||||
|
expect(el).toBeDisabled();
|
||||||
|
});
|
||||||
|
|
||||||
|
await userEvent.type(
|
||||||
|
getAllByRole('textbox').find((el) => el.getAttribute('name') === 'metadata')!,
|
||||||
|
'<?xml version="1.0"?>',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(checkbox).toBeDisabled();
|
||||||
|
expect(btnTest).toBeDisabled();
|
||||||
|
expect(btnSave).toBeEnabled();
|
||||||
|
|
||||||
|
const saveSpy = vi.spyOn(ssoStore, 'saveSamlConfig');
|
||||||
|
const getSpy = vi.spyOn(ssoStore, 'getSamlConfig').mockResolvedValue(samlConfig);
|
||||||
|
await userEvent.click(btnSave);
|
||||||
|
|
||||||
|
expect(saveSpy).toHaveBeenCalled();
|
||||||
|
expect(getSpy).toHaveBeenCalled();
|
||||||
|
expect(checkbox).toBeEnabled();
|
||||||
|
expect(btnTest).toBeEnabled();
|
||||||
|
expect(btnSave).toBeEnabled();
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue