From a8df151c17eb94c40a6dd255a278a2b8522e34b4 Mon Sep 17 00:00:00 2001 From: DarkPhoenix2704 Date: Wed, 7 Feb 2024 12:26:47 +0000 Subject: [PATCH] feat(test): playwright for saml, oidc --- packages/nc-gui/components/nc/Select.vue | 2 +- .../pages/Account/Authentication.ts | 130 ++++++++++++++++++ tests/playwright/pages/Account/index.ts | 3 + 3 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 tests/playwright/pages/Account/Authentication.ts diff --git a/packages/nc-gui/components/nc/Select.vue b/packages/nc-gui/components/nc/Select.vue index 45b69d6a12..41b7f198a8 100644 --- a/packages/nc-gui/components/nc/Select.vue +++ b/packages/nc-gui/components/nc/Select.vue @@ -86,7 +86,7 @@ const onChange = (value: string) => { } .ant-select-selection-item { - @apply font-medium pr-3 bg-gray-200 text-gray-800 rounded-md; + @apply font-medium pr-3 rounded-md; } .ant-select-selection-placeholder { diff --git a/tests/playwright/pages/Account/Authentication.ts b/tests/playwright/pages/Account/Authentication.ts new file mode 100644 index 0000000000..1bbb9f9c31 --- /dev/null +++ b/tests/playwright/pages/Account/Authentication.ts @@ -0,0 +1,130 @@ +import BasePage from '../Base'; +import { AccountPage } from './index'; +import * as assert from 'assert'; +import { expect } from '@playwright/test'; + +export class AccountAuthenticationPage extends BasePage { + private accountPage: AccountPage; + + constructor(accountPage: AccountPage) { + super(accountPage.rootPage); + this.accountPage = accountPage; + } + + async goto() { + await this.waitForResponse({ + uiAction: () => this.rootPage.goto('/#/account/authentication', { waitUntil: 'networkidle' }), + httpMethodsToMatch: ['GET'], + requestUrlPathToMatch: '/api/v2/sso-client', + }); + } + + get() { + return this.accountPage.get().locator(`[data-test-id="nc-authentication"]`); + } + + async verifySAMLProviderCount({ count }: { count: number }) { + expect(await this.get().locator('.nc-saml-provider').count()).toBe(count); + } + + async verifyOIDCProviderCount({ count }: { count: number }) { + expect(await this.get().locator('.nc-oidc-provider').count()).toBe(count); + } + + async getProvider(provider: 'saml' | 'oidc', title: string) { + return this.rootPage.locator(`[data-test-id="nc-${provider}-provider-${title}"]`); + } + + async deleteProvider(provider: 'saml' | 'oidc', title: string) { + await this.rootPage.locator(`.nc-${provider}-${title}-more-option`).click(); + await this.waitForResponse({ + uiAction: () => this.rootPage.locator(`[data-test-id="nc-${provider}-delete"]`).click(), + httpMethodsToMatch: ['DELETE'], + requestUrlPathToMatch: `/api/v2/sso-client/`, + }); + } + + async toggleProvider(provider: 'saml' | 'oidc', title: string) { + await this.waitForResponse({ + uiAction: () => this.get().locator(`.nc-${provider}-${title}-enable .nc-switch`).click(), + httpMethodsToMatch: ['PATCH'], + requestUrlPathToMatch: `/api/v2/sso-client/`, + }); + } + + async selectScope({ type, locator }: { type: string[] }) { + await this.rootPage.locator('.ant-select-selector').click(); + + await this.rootPage.locator('.ant-select-selection-search-input[aria-expanded="true"]').waitFor(); + for (const t of type) { + await this.rootPage.locator('.rc-virtual-list-holder-inner > div').locator(`text="${t}"`).click(); + } + } + + async createSAMLProvider(p: { title: string; url?: string; xml?: string }) { + const newSamlBtn = this.get().locator('[data-test-id="nc-new-saml-provider"]'); + + await newSamlBtn.click(); + + const samlModal = this.accountPage.rootPage.locator('.nc-saml-modal'); + + await samlModal.locator('[data-test-id="nc-saml-title"]').fill(p.title); + if (p.url) { + await samlModal.locator('[data-test-id="nc-saml-metadata-url"]').fill(p.url); + } + if (p.xml) { + await samlModal.locator('[data-test-id="nc-saml-xml"]').fill(p.xml); + } + + await this.waitForResponse({ + uiAction: () => samlModal.locator('[data-test-id="nc-saml-submit"]').click(), + httpMethodsToMatch: ['GET'], + requestUrlPathToMatch: '/api/v2/sso-client', + }); + } + + async createOIDCProvider(p: { + title: string; + clientId: string; + clientSecret: string; + authUrl: string; + userInfoUrl: string; + tokenUrl: string; + jwkUrl: string; + scopes: Array; + userAttributes: string; + }) { + const newOIDCBtn = this.get().locator('[data-test-id="nc-new-oidc-provider"]'); + + await newOIDCBtn.click(); + + const oidcModal = this.accountPage.rootPage.locator('.nc-oidc-modal'); + + await oidcModal.locator('[data-test-id="nc-oidc-title"]').fill(p.title); + + await oidcModal.locator('[data-test-id="nc-oidc-client-id"]').fill(p.clientId); + + await oidcModal.locator('[data-test-id="nc-oidc-client-secret"]').fill(p.clientSecret); + + await oidcModal.locator('[data-test-id="nc-oidc-authUrl"]').fill(p.authUrl); + + await oidcModal.locator('[data-test-id="nc-oidc-tokenUrl"]').fill(p.tokenUrl); + + await oidcModal.locator('[data-test-id="nc-oidc-userInfoUrl"]').fill(p.userInfoUrl); + + await oidcModal.locator('[data-test-id="nc-oidc-jwkUrl"]').fill(p.jwkUrl); + + await this.selectScope({ + type: p.scopes, + locator: oidcModal.locator('[data-test-id="nc-oidc-scope"]'), + }); + + await oidcModal.locator('[data-test-id="nc-oidc-user-attribute"]').fill(p.userAttributes); + + await this.waitForResponse({ + uiAction: () => oidcModal.locator('[data-test-id="nc-oidc-save-btn"]').click(), + httpMethodsToMatch: ['GET'], + requestUrlPathToMatch: '/api/v2/sso-client', + }); + } +} diff --git a/tests/playwright/pages/Account/index.ts b/tests/playwright/pages/Account/index.ts index 01e404d0ef..1eea23865c 100644 --- a/tests/playwright/pages/Account/index.ts +++ b/tests/playwright/pages/Account/index.ts @@ -5,6 +5,7 @@ import { AccountTokenPage } from './Token'; import { AccountUsersPage } from './Users'; import { AccountAppStorePage } from './AppStore'; import { AccountLicensePage } from './License'; +import { AccountAuthenticationPage } from './Authentication'; export class AccountPage extends BasePage { readonly settings: AccountSettingsPage; @@ -12,6 +13,7 @@ export class AccountPage extends BasePage { readonly users: AccountUsersPage; readonly appStore: AccountAppStorePage; readonly license: AccountLicensePage; + readonly authentication: AccountAuthenticationPage; constructor(page: Page) { super(page); @@ -20,6 +22,7 @@ export class AccountPage extends BasePage { this.users = new AccountUsersPage(this); this.appStore = new AccountAppStorePage(this); this.license = new AccountLicensePage(this); + this.authentication = new AccountAuthenticationPage(this); } get() {