From 6ec35e0b3fba78e6cd91be1102f44d6e31135756 Mon Sep 17 00:00:00 2001 From: Robb Hamilton Date: Tue, 17 Oct 2023 15:54:48 -0400 Subject: [PATCH] CONSOLE-3788: migrate tests --- .../tests/cluster-settings.scenario.ts | 94 ------- .../tests/environment.scenario.ts | 187 -------------- .../integration-tests/tests/oauth.scenario.ts | 234 ------------------ .../views/cluster-settings.view.ts | 18 -- .../integration-tests/views/oauth.view.ts | 46 ---- .../cluster-settings/cluster-settings.cy.ts | 67 +++++ .../tests/cluster-settings/oauth.cy.ts | 84 +++++++ .../tests/crud/environment.cy.ts | 78 ++++++ .../views/environment.ts | 61 +++++ .../integration-tests-cypress/views/oauth.ts | 20 ++ 10 files changed, 310 insertions(+), 579 deletions(-) delete mode 100644 frontend/integration-tests/tests/cluster-settings.scenario.ts delete mode 100644 frontend/integration-tests/tests/environment.scenario.ts delete mode 100644 frontend/integration-tests/tests/oauth.scenario.ts delete mode 100644 frontend/integration-tests/views/cluster-settings.view.ts delete mode 100644 frontend/integration-tests/views/oauth.view.ts create mode 100644 frontend/packages/integration-tests-cypress/tests/cluster-settings/cluster-settings.cy.ts create mode 100644 frontend/packages/integration-tests-cypress/tests/cluster-settings/oauth.cy.ts create mode 100644 frontend/packages/integration-tests-cypress/tests/crud/environment.cy.ts create mode 100644 frontend/packages/integration-tests-cypress/views/environment.ts create mode 100644 frontend/packages/integration-tests-cypress/views/oauth.ts diff --git a/frontend/integration-tests/tests/cluster-settings.scenario.ts b/frontend/integration-tests/tests/cluster-settings.scenario.ts deleted file mode 100644 index 4f6b3ce0c8ea..000000000000 --- a/frontend/integration-tests/tests/cluster-settings.scenario.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { browser } from 'protractor'; - -import { appHost, checkLogs, checkErrors } from '../protractor.conf'; -import * as crudView from '../views/crud.view'; -import * as clusterSettingsView from '../views/cluster-settings.view'; -import * as horizontalnavView from '../views/horizontal-nav.view'; - -describe('Cluster Settings', () => { - beforeEach(async () => { - await browser.get(`${appHost}/settings/cluster`); - await crudView.isLoaded(); - }); - - afterEach(() => { - checkLogs(); - checkErrors(); - }); - - it('display page title, horizontal navigation tab headings and pages', async () => { - expect(clusterSettingsView.heading.isPresent()).toBe(true); - await horizontalnavView.clickHorizontalTab('Details'); - await crudView.isLoaded(); - await horizontalnavView.clickHorizontalTab('ClusterOperators'); - await crudView.isLoaded(); - await horizontalnavView.clickHorizontalTab('Configuration'); - await crudView.isLoaded(); - }); - it('display overview channel update modal and click cancel', async () => { - await horizontalnavView.clickHorizontalTab('Details'); - await crudView.isLoaded(); - expect(clusterSettingsView.channelUpdateLink.isDisplayed()).toBe(true); - await clusterSettingsView.channelUpdateLink.click(); - await crudView.isLoaded(); - - expect(clusterSettingsView.channelPopupCancelButton.isDisplayed()).toBe(true); - await clusterSettingsView.channelPopupCancelButton.click(); - await crudView.isLoaded(); - }); - it('display Cluster Operators page, click resource item link to display details. Check if the resource link title equals the details page header', async () => { - await horizontalnavView.clickHorizontalTab('ClusterOperators'); - await crudView.isLoaded(); - - expect(clusterSettingsView.clusterOperatorResourceLink.isDisplayed()).toBe(true); - await clusterSettingsView.clusterOperatorResourceLink.click(); - await crudView.isLoaded(); - - expect(clusterSettingsView.clusterResourceDetailsTitle.isDisplayed()).toBe(true); - expect(clusterSettingsView.clusterResourceDetailsTitle.getText()).toBe('console'); - - await horizontalnavView.clickHorizontalTab('YAML'); - await crudView.isLoaded(); - }); - it('display Configuration page, click Configuration Resource item link and display details. Check if the resource link title equals the details page header', async () => { - await horizontalnavView.clickHorizontalTab('Configuration'); - await crudView.isLoaded(); - - expect(clusterSettingsView.globalConfigResourceLink.isDisplayed()).toBe(true); - await clusterSettingsView.globalConfigResourceLink.click(); - await crudView.isLoaded(); - - expect(clusterSettingsView.clusterResourceDetailsTitle.isDisplayed()).toBe(true); - expect(clusterSettingsView.clusterResourceDetailsTitle.getText()).toBe('cluster'); - - await horizontalnavView.clickHorizontalTab('YAML'); - await crudView.isLoaded(); - }); - it('display Configuration page, click dropdown link to edit resource and display details, and check if details header is correct.', async () => { - await horizontalnavView.clickHorizontalTab('Configuration'); - await crudView.isLoaded(); - - await clusterSettingsView.globalConfigResourceRow.click(); - await crudView.isLoaded(); - - expect(crudView.actionForLabel('Edit Console resource').isDisplayed()).toBe(true); - await crudView.actionForLabel('Edit Console resource').click(); - await crudView.isLoaded(); - - expect(clusterSettingsView.clusterResourceDetailsTitle.isDisplayed()).toBe(true); - expect(clusterSettingsView.clusterResourceDetailsTitle.getText()).toBe('cluster'); - }); - it('display Configuration page, click Explore Console API in dropdown link and display details, and check if details header is correct.', async () => { - await horizontalnavView.clickHorizontalTab('Configuration'); - await crudView.isLoaded(); - - await clusterSettingsView.globalConfigResourceRow.click(); - await crudView.isLoaded(); - - expect(crudView.actionForLabel('Explore Console API').isDisplayed()).toBe(true); - await crudView.actionForLabel('Explore Console API').click(); - - await clusterSettingsView.globalConfigDetailsTitleIsLoaded(); - expect(clusterSettingsView.globalConfigDetailsTitle.getText()).toBe('Console'); - }); -}); diff --git a/frontend/integration-tests/tests/environment.scenario.ts b/frontend/integration-tests/tests/environment.scenario.ts deleted file mode 100644 index 10a9a123e1c8..000000000000 --- a/frontend/integration-tests/tests/environment.scenario.ts +++ /dev/null @@ -1,187 +0,0 @@ -import { browser, ExpectedConditions as until } from 'protractor'; -import { safeLoad, safeDump } from 'js-yaml'; -import * as _ from 'lodash'; - -import { appHost, testName, checkLogs, checkErrors } from '../protractor.conf'; -import * as crudView from '../views/crud.view'; -import * as environmentView from '../views/environment.view'; -import * as yamlView from '../views/yaml.view'; -import { execSync } from 'child_process'; - -const BROWSER_TIMEOUT = 15000; -const WORKLOAD_NAME = `env-${testName}`; -const Actions = { - add: 'add', - delete: 'delete', - deleteFrom: 'deleteFrom', - addFrom: 'addFrom', -}; - -describe('Interacting with the environment variable editor', () => { - beforeAll(async () => { - await browser.get(`${appHost}/k8s/ns/${testName}/deployments`); - await crudView.isLoaded(); - await crudView.createYAMLButton.click(); - await crudView.isLoaded(); - await crudView.createYAMLSwitchRadio.click(); - await yamlView.isSwitchViewLoaded(); - const content = await yamlView.getEditorContent(); - const newContent = _.defaultsDeep( - {}, - { metadata: { name: WORKLOAD_NAME, labels: { ['lbl-env']: testName } } }, - safeLoad(content), - ); - await yamlView.setEditorContent(safeDump(newContent)); - await crudView.saveChangesBtn.click(); - // Wait until the resource is created and the details page loads before continuing. - await crudView.isDetailsPageLoaded(); - execSync( - `oc create cm my-config --from-literal=cmk1=config1 --from-literal=cmk2=config2 -n ${testName}`, - ); - execSync( - `oc create secret generic my-secret --from-literal=key1=supersecret --from-literal=key2=topsecret -n ${testName}`, - ); - checkLogs(); - checkErrors(); - }); - - afterEach(() => { - checkLogs(); - checkErrors(); - }); - - afterAll(async () => { - await browser.get(`${appHost}/k8s/ns/${testName}/deployments`); - await crudView.isLoaded(); - await crudView.textFilter.sendKeys(WORKLOAD_NAME); - await browser.wait( - until.elementToBeClickable(crudView.resourceRowNamesAndNs.first()), - BROWSER_TIMEOUT, - ); - await crudView.deleteRow('Deployment')(WORKLOAD_NAME); - execSync(`oc delete cm my-config -n ${testName}`); - execSync(`oc delete secret my-secret -n ${testName}`); - checkLogs(); - checkErrors(); - }); - - const present = true; - const validateKeyAndValue = async (key: string, value: string, isPresent: boolean) => { - let keyFound = 0; - - const envKey = await environmentView.rowsKey.getAttribute('value'); - const envValue = await environmentView.rowsValue.getAttribute('value'); - - if (envKey === key) { - keyFound = keyFound + 1; - expect(envValue).toBe(value); - } - - if (isPresent) { - expect(keyFound).toEqual(1); - } else { - expect(keyFound).toEqual(0); - } - }; - - const validateValueFrom = async (valueFrom: string, prefix: string, isPresent: boolean) => { - const resourceText = await environmentView.resources.last().getText(); - const prefixText = await environmentView.prefix.getAttribute('value'); - if (isPresent) { - expect(resourceText).toEqual(valueFrom); - expect(prefixText).toEqual(prefix); - } else { - expect(resourceText).toEqual('container'); - expect(prefixText).toEqual(''); - } - }; - - const environmentEditor = async (action: string, key: string, value: string) => { - await browser.get(`${appHost}/k8s/ns/${testName}/deployments/${WORKLOAD_NAME}/environment`); - - switch (action) { - case Actions.add: { - await environmentView.addVariable(key, value); - break; - } - case Actions.delete: { - await environmentView.deleteVariable(); - break; - } - case Actions.deleteFrom: { - await environmentView.deleteFromVariable(); - break; - } - case Actions.addFrom: { - await environmentView.addVariableFrom(key, value); - break; - } - default: { - throw new Error(`Invalid action [${action}]`); - } - } - - await environmentView.isLoaded(); - await crudView.isLoaded(); - }; - - describe('When a variable is added', () => { - it('shows the correct variables', async () => { - const key = 'KEY'; - const value = 'value'; - await environmentEditor(Actions.add, key, value); - await environmentView.isLoaded(); - await validateKeyAndValue(key, value, present); - }); - }); - - describe('When a variable is deleted', () => { - it('does not show any variables', async () => { - const key = 'KEY'; - const value = 'value'; - await environmentEditor(Actions.delete, key, value); - await environmentView.isLoaded(); - await validateKeyAndValue(key, value, !present); - }); - }); - - describe('When a variable is added from a config map', () => { - it('shows the correct variables', async () => { - const resourceName = 'my-config'; - const envPrefix = 'testcm'; - await environmentEditor(Actions.addFrom, resourceName, envPrefix); - await environmentView.isLoaded(); - await validateValueFrom(resourceName, envPrefix, present); - }); - }); - - describe('When a variable is deleted from a config map', () => { - it('shows the correct variables', async () => { - const resourceName = 'my-config'; - const envPrefix = 'testcm'; - await environmentEditor(Actions.deleteFrom, resourceName, envPrefix); - await environmentView.isLoaded(); - await validateValueFrom(resourceName, envPrefix, !present); - }); - }); - - describe('When a variable is added from a secret', () => { - it('shows the correct variables', async () => { - const resourceName = 'my-secret'; - const envPrefix = 'testsecret'; - await environmentEditor(Actions.addFrom, resourceName, envPrefix); - await environmentView.isLoaded(); - await validateValueFrom(resourceName, envPrefix, true); - }); - }); - - describe('When a variable is deleted from a secret', () => { - it('shows the correct variables', async () => { - const resourceName = 'my-secret'; - const envPrefix = 'testsecret'; - await environmentEditor(Actions.deleteFrom, resourceName, envPrefix); - await environmentView.isLoaded(); - await validateValueFrom(resourceName, envPrefix, false); - }); - }); -}); diff --git a/frontend/integration-tests/tests/oauth.scenario.ts b/frontend/integration-tests/tests/oauth.scenario.ts deleted file mode 100644 index cca5d2bfe0b8..000000000000 --- a/frontend/integration-tests/tests/oauth.scenario.ts +++ /dev/null @@ -1,234 +0,0 @@ -import { browser, ExpectedConditions as until } from 'protractor'; -import { execSync } from 'child_process'; - -import { appHost, checkLogs, checkErrors, testName } from '../protractor.conf'; -import * as crudView from '../views/crud.view'; -import * as oauthView from '../views/oauth.view'; - -describe('OAuth', () => { - const oauthSettingsURL = `${appHost}/k8s/cluster/config.openshift.io~v1~OAuth/cluster`; - let originalOAuthConfig: any; - beforeAll(() => { - originalOAuthConfig = JSON.parse(execSync('kubectl get -o json oauths cluster').toString()); - }); - - afterAll(() => { - const idpJSON = JSON.stringify(originalOAuthConfig.spec.identityProviders); - execSync( - `kubectl patch oauths cluster --type json -p='[{ op: 'replace', path: '/spec/identityProviders', value: ${idpJSON}}]'`, - ); - }); - - afterEach(() => { - checkLogs(); - checkErrors(); - }); - - // TODO: Add tests for HTPasswd and Request Header identity providers. - // These IDPs require file upload. - - describe('BasicAuth IDP', () => { - const idpName = `basic-auth-${testName}`; - it('creates a Basic Authentication IDP', async () => { - await browser.get(oauthSettingsURL); - await browser.wait(until.elementToBeClickable(oauthView.addIDPDropdown)); - await oauthView.addIDPDropdown.click(); - await browser.wait(until.elementToBeClickable(oauthView.basicAuthLink)); - await oauthView.basicAuthLink.click(); - await browser.wait(until.elementToBeClickable(oauthView.idpNameInput)); - await oauthView.idpNameInput.clear(); - await oauthView.idpNameInput.sendKeys(idpName); - await oauthView.basicAuthURLInput.sendKeys('https://example.com'); - await oauthView.addIDPButton.click(); - await crudView.isLoaded(); - expect(oauthView.errorMessage.isPresent()).toBe(false); - }); - - it('shows the BasicAuth IDP on the OAuth settings page', async () => { - await browser.get(oauthSettingsURL); - await crudView.isLoaded(); - await browser.wait(until.presenceOf(crudView.resourceTitle)); - expect(browser.getCurrentUrl()).toContain('config.openshift.io~v1~OAuth/cluster'); - expect(oauthView.idpTableCellName(idpName).getText()).toEqual(idpName); - expect(oauthView.idpTableCellType(idpName).getText()).toEqual('BasicAuth'); - expect(oauthView.idpTableCellMapping(idpName).getText()).toEqual('claim'); - }); - }); - - describe('GitHub IDP', () => { - const idpName = `github-${testName}`; - it('creates a GitHub IDP', async () => { - await browser.get(oauthSettingsURL); - await browser.wait(until.elementToBeClickable(oauthView.addIDPDropdown)); - await oauthView.addIDPDropdown.click(); - await browser.wait(until.elementToBeClickable(oauthView.githubLink)); - await oauthView.githubLink.click(); - await browser.wait(until.elementToBeClickable(oauthView.idpNameInput)); - await oauthView.idpNameInput.clear(); - await oauthView.idpNameInput.sendKeys(idpName); - await oauthView.githubClientIDInput.sendKeys('my-client-id'); - await oauthView.githubClientSecretInput.sendKeys('my-client-secret'); - await oauthView.githubOrganizationInput.sendKeys('my-organization'); - await oauthView.addIDPButton.click(); - await crudView.isLoaded(); - expect(oauthView.errorMessage.isPresent()).toBe(false); - }); - - it('shows the GitHub IDP on the OAuth settings page', async () => { - await browser.get(oauthSettingsURL); - await crudView.isLoaded(); - await browser.wait(until.presenceOf(crudView.resourceTitle)); - expect(browser.getCurrentUrl()).toContain('config.openshift.io~v1~OAuth/cluster'); - expect(oauthView.idpTableCellName(idpName).getText()).toEqual(idpName); - expect(oauthView.idpTableCellType(idpName).getText()).toEqual('GitHub'); - expect(oauthView.idpTableCellMapping(idpName).getText()).toEqual('claim'); - }); - }); - - describe('GitLab IDP', () => { - const idpName = `gitlab-${testName}`; - it('creates a GitLab IDP', async () => { - await browser.get(oauthSettingsURL); - await browser.wait(until.elementToBeClickable(oauthView.addIDPDropdown)); - await oauthView.addIDPDropdown.click(); - await browser.wait(until.elementToBeClickable(oauthView.gitlabLink)); - await oauthView.gitlabLink.click(); - await browser.wait(until.elementToBeClickable(oauthView.idpNameInput)); - await oauthView.idpNameInput.clear(); - await oauthView.idpNameInput.sendKeys(idpName); - await oauthView.gitlabURLInput.sendKeys('https://example.com'); - await oauthView.gitlabClientIDInput.sendKeys('my-client-id'); - await oauthView.gitlabClientSecretInput.sendKeys('my-client-secret'); - await oauthView.addIDPButton.click(); - await crudView.isLoaded(); - expect(oauthView.errorMessage.isPresent()).toBe(false); - }); - - it('shows the GitLab IDP on the OAuth settings page', async () => { - await browser.get(oauthSettingsURL); - await crudView.isLoaded(); - await browser.wait(until.presenceOf(crudView.resourceTitle)); - expect(browser.getCurrentUrl()).toContain('config.openshift.io~v1~OAuth/cluster'); - expect(oauthView.idpTableCellName(idpName).getText()).toEqual(idpName); - expect(oauthView.idpTableCellType(idpName).getText()).toEqual('GitLab'); - expect(oauthView.idpTableCellMapping(idpName).getText()).toEqual('claim'); - }); - }); - - describe('Google IDP', () => { - const idpName = `google-${testName}`; - it('creates a Google IDP', async () => { - await browser.get(oauthSettingsURL); - await browser.wait(until.elementToBeClickable(oauthView.addIDPDropdown)); - await oauthView.addIDPDropdown.click(); - await browser.wait(until.elementToBeClickable(oauthView.googleLink)); - await oauthView.googleLink.click(); - await browser.wait(until.elementToBeClickable(oauthView.idpNameInput)); - await oauthView.idpNameInput.clear(); - await oauthView.idpNameInput.sendKeys(idpName); - await oauthView.googleClientIDInput.sendKeys('my-client-id'); - await oauthView.googleClientSecretInput.sendKeys('my-client-secret'); - await oauthView.googleHostedDomainInput.sendKeys('example.com'); - await oauthView.addIDPButton.click(); - await crudView.isLoaded(); - expect(oauthView.errorMessage.isPresent()).toBe(false); - }); - - it('shows the Google IDP on the OAuth settings page', async () => { - await browser.get(oauthSettingsURL); - await crudView.isLoaded(); - await browser.wait(until.presenceOf(crudView.resourceTitle)); - expect(browser.getCurrentUrl()).toContain('config.openshift.io~v1~OAuth/cluster'); - expect(oauthView.idpTableCellName(idpName).getText()).toEqual(idpName); - expect(oauthView.idpTableCellType(idpName).getText()).toEqual('Google'); - expect(oauthView.idpTableCellMapping(idpName).getText()).toEqual('claim'); - }); - }); - - describe('Keystone IDP', () => { - const idpName = `keystone-${testName}`; - it('creates a Keystone IDP', async () => { - await browser.get(oauthSettingsURL); - await browser.wait(until.elementToBeClickable(oauthView.addIDPDropdown)); - await oauthView.addIDPDropdown.click(); - await browser.wait(until.elementToBeClickable(oauthView.keystoneLink)); - await oauthView.keystoneLink.click(); - await browser.wait(until.elementToBeClickable(oauthView.idpNameInput)); - await oauthView.idpNameInput.clear(); - await oauthView.idpNameInput.sendKeys(idpName); - await oauthView.keystoneDomainInput.sendKeys('example.com'); - await oauthView.keystoneURLInput.sendKeys('https://example.com'); - await oauthView.addIDPButton.click(); - await crudView.isLoaded(); - expect(oauthView.errorMessage.isPresent()).toBe(false); - }); - - it('shows the Keystone IDP on the OAuth settings page', async () => { - await browser.get(oauthSettingsURL); - await crudView.isLoaded(); - await browser.wait(until.presenceOf(crudView.resourceTitle)); - expect(browser.getCurrentUrl()).toContain('config.openshift.io~v1~OAuth/cluster'); - expect(oauthView.idpTableCellName(idpName).getText()).toEqual(idpName); - expect(oauthView.idpTableCellType(idpName).getText()).toEqual('Keystone'); - expect(oauthView.idpTableCellMapping(idpName).getText()).toEqual('claim'); - }); - }); - - describe('LDAP IDP', () => { - const idpName = `ldap-${testName}`; - it('creates a LDAP IDP', async () => { - await browser.get(oauthSettingsURL); - await browser.wait(until.elementToBeClickable(oauthView.addIDPDropdown)); - await oauthView.addIDPDropdown.click(); - await browser.wait(until.elementToBeClickable(oauthView.ldapLink)); - await oauthView.ldapLink.click(); - await browser.wait(until.elementToBeClickable(oauthView.idpNameInput)); - await oauthView.idpNameInput.clear(); - await oauthView.idpNameInput.sendKeys(idpName); - await oauthView.ldapURLInput.sendKeys('ldap://ldap.example.com/o=Acme?cn?sub?(enabled=true)'); - await oauthView.addIDPButton.click(); - await crudView.isLoaded(); - expect(oauthView.errorMessage.isPresent()).toBe(false); - }); - - it('shows the LDAP IDP on the OAuth settings page', async () => { - await browser.get(oauthSettingsURL); - await crudView.isLoaded(); - await browser.wait(until.presenceOf(crudView.resourceTitle)); - expect(browser.getCurrentUrl()).toContain('config.openshift.io~v1~OAuth/cluster'); - expect(oauthView.idpTableCellName(idpName).getText()).toEqual(idpName); - expect(oauthView.idpTableCellType(idpName).getText()).toEqual('LDAP'); - expect(oauthView.idpTableCellMapping(idpName).getText()).toEqual('claim'); - }); - }); - - describe('OpenID IDP', () => { - const idpName = `oidc-${testName}`; - it('creates a OpenID IDP', async () => { - await browser.get(oauthSettingsURL); - await browser.wait(until.elementToBeClickable(oauthView.addIDPDropdown)); - await oauthView.addIDPDropdown.click(); - await browser.wait(until.elementToBeClickable(oauthView.oidcLink)); - await oauthView.oidcLink.click(); - await browser.wait(until.elementToBeClickable(oauthView.idpNameInput)); - await oauthView.idpNameInput.clear(); - await oauthView.idpNameInput.sendKeys(idpName); - await oauthView.oidcClientIDInput.sendKeys('my-client-id'); - await oauthView.oidcClientSecretInput.sendKeys('my-client-secret'); - await oauthView.oidcIssuerInput.sendKeys('https://example.com'); - await oauthView.addIDPButton.click(); - await crudView.isLoaded(); - expect(oauthView.errorMessage.isPresent()).toBe(false); - }); - - it('shows the OpenID IDP on the OAuth settings page', async () => { - await browser.get(oauthSettingsURL); - await crudView.isLoaded(); - await browser.wait(until.presenceOf(crudView.resourceTitle)); - expect(browser.getCurrentUrl()).toContain('config.openshift.io~v1~OAuth/cluster'); - expect(oauthView.idpTableCellName(idpName).getText()).toEqual(idpName); - expect(oauthView.idpTableCellType(idpName).getText()).toEqual('OpenID'); - expect(oauthView.idpTableCellMapping(idpName).getText()).toEqual('claim'); - }); - }); -}); diff --git a/frontend/integration-tests/views/cluster-settings.view.ts b/frontend/integration-tests/views/cluster-settings.view.ts deleted file mode 100644 index 82fbd7151457..000000000000 --- a/frontend/integration-tests/views/cluster-settings.view.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { element, by, browser, $$, $, ExpectedConditions as until } from 'protractor'; -import { waitForNone } from '../protractor.conf'; - -export const heading = element( - by.cssContainingText('[data-test-id="cluster-settings-page-heading"]', 'Cluster Settings'), -); -export const isLoaded = async () => await browser.wait(waitForNone($$('.co-m-loader'))); -export const channelUpdateLink = $('[data-test-id="current-channel-update-link"]'); -export const channelPopupCancelButton = $('[data-test-id="modal-cancel-action"]'); -export const globalConfigResourceRow = $('[data-test-action="Console"]').$$( - '[data-test-id="kebab-button"]', -); -export const clusterOperatorResourceLink = $('[data-test-id="console"]'); -export const globalConfigResourceLink = $('[data-test-id="Console"]'); -export const clusterResourceDetailsTitle = $('[data-test-id="resource-title"]'); -export const globalConfigDetailsTitle = $('[data-test-id="api-explorer-resource-title"]'); -export const globalConfigDetailsTitleIsLoaded = async () => - await browser.wait(until.presenceOf(globalConfigDetailsTitle)); diff --git a/frontend/integration-tests/views/oauth.view.ts b/frontend/integration-tests/views/oauth.view.ts deleted file mode 100644 index a72ec0c1e747..000000000000 --- a/frontend/integration-tests/views/oauth.view.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { $ } from 'protractor'; - -export const addIDPDropdown = $('[data-test-id="dropdown-button"]'); -export const idpNameInput = $('#idp-name'); -export const addIDPButton = $('[data-test-id="add-idp"]'); -export const idpTableCellName = (name: string) => $(`[data-test-idp-name="${name}"]`); -export const idpTableCellType = (name: string) => $(`[data-test-idp-type-for="${name}"]`); -export const idpTableCellMapping = (name: string) => $(`[data-test-idp-mapping-for="${name}"]`); -export const errorMessage = $('.pf-c-alert.pf-m-danger'); - -// BasicAuth IDP -export const basicAuthLink = $('[data-test-id="basicauth"]'); -export const basicAuthURLInput = $('#url'); - -// GitHub IDP -export const githubLink = $('[data-test-id="github"]'); -export const githubClientIDInput = $('#client-id'); -export const githubClientSecretInput = $('#client-secret'); -export const githubOrganizationInput = $('[data-test-list-input-for="Organization"]'); - -// GitLab IDP -export const gitlabLink = $('[data-test-id="gitlab"]'); -export const gitlabURLInput = $('#url'); -export const gitlabClientIDInput = $('#client-id'); -export const gitlabClientSecretInput = $('#client-secret'); - -// Google IDP -export const googleLink = $('[data-test-id="google"]'); -export const googleClientIDInput = $('#client-id'); -export const googleClientSecretInput = $('#client-secret'); -export const googleHostedDomainInput = $('#hosted-domain'); - -// Keystone IDP -export const keystoneLink = $('[data-test-id="keystone"]'); -export const keystoneDomainInput = $('#domain-name'); -export const keystoneURLInput = $('#url'); - -// LDAP IDP -export const ldapLink = $('[data-test-id="ldap"]'); -export const ldapURLInput = $('#url'); - -// OpenID Connect IDP -export const oidcLink = $('[data-test-id="oidconnect"]'); -export const oidcClientIDInput = $('#client-id'); -export const oidcClientSecretInput = $('#client-secret'); -export const oidcIssuerInput = $('#issuer'); diff --git a/frontend/packages/integration-tests-cypress/tests/cluster-settings/cluster-settings.cy.ts b/frontend/packages/integration-tests-cypress/tests/cluster-settings/cluster-settings.cy.ts new file mode 100644 index 000000000000..42cd519840d1 --- /dev/null +++ b/frontend/packages/integration-tests-cypress/tests/cluster-settings/cluster-settings.cy.ts @@ -0,0 +1,67 @@ +import { checkErrors } from '../../support'; +import { detailsPage } from '../../views/details-page'; + +describe('Cluster Settings', () => { + before(() => { + cy.initAdmin(); + }); + + beforeEach(() => { + cy.visit('/settings/cluster'); + }); + + afterEach(() => { + checkErrors(); + }); + + it('displays page title, horizontal navigation tab headings and pages', () => { + cy.byLegacyTestID('cluster-settings-page-heading').should('contain.text', 'Cluster Settings'); + detailsPage.selectTab('Details'); + detailsPage.isLoaded(); + detailsPage.selectTab('ClusterOperators'); + detailsPage.isLoaded(); + detailsPage.selectTab('Configuration'); + detailsPage.isLoaded(); + }); + + it('displays channel update modal and closes it', () => { + detailsPage.selectTab('Details'); + cy.byLegacyTestID('current-channel-update-link').should('be.visible').click(); + cy.byLegacyTestID('modal-cancel-action').should('be.visible').click(); + }); + + it('displays Cluster Operators page and console Operator details page', () => { + detailsPage.selectTab('ClusterOperators'); + cy.byLegacyTestID('console').should('be.visible').click(); + detailsPage.titleShouldContain('console'); + detailsPage.selectTab('YAML'); + detailsPage.isLoaded(); + }); + + it('displays Configuration page and ClusterVersion configuration details page', () => { + detailsPage.selectTab('Configuration'); + cy.byLegacyTestID('ClusterVersion').should('be.visible').click(); + detailsPage.selectTab('YAML'); + detailsPage.isLoaded(); + }); + + it('displays Configuration page and ClusterVersion Edit ClusterVersion resource details page', () => { + detailsPage.selectTab('Configuration'); + detailsPage.isLoaded(); + cy.byTestActionID('ClusterVersion').within(() => { + cy.get('[data-test-id="kebab-button"]').click(); + }); + cy.byTestActionID('Edit ClusterVersion resource').click(); + detailsPage.titleShouldContain('version'); + }); + + it('displays Configuration page and ClusterVersion Explore Console API details page', () => { + detailsPage.selectTab('Configuration'); + detailsPage.isLoaded(); + cy.byTestActionID('ClusterVersion').within(() => { + cy.get('[data-test-id="kebab-button"]').click(); + }); + cy.byTestActionID('Explore ClusterVersion API').click(); + detailsPage.titleShouldContain('ClusterVersion'); + }); +}); diff --git a/frontend/packages/integration-tests-cypress/tests/cluster-settings/oauth.cy.ts b/frontend/packages/integration-tests-cypress/tests/cluster-settings/oauth.cy.ts new file mode 100644 index 000000000000..2504b7489340 --- /dev/null +++ b/frontend/packages/integration-tests-cypress/tests/cluster-settings/oauth.cy.ts @@ -0,0 +1,84 @@ +import { checkErrors, testName } from '../../support'; +import { oauth } from '../../views/oauth'; + +describe('OAuth', () => { + let originalOAuthConfig: any; + + before(() => { + cy.exec('oc get oauths cluster -o json').then((result) => { + originalOAuthConfig = JSON.parse(result.stdout); + }); + }); + + afterEach(() => { + checkErrors(); + }); + + after(() => { + const idpJSON = JSON.stringify(originalOAuthConfig?.spec?.identityProviders) ?? '[]'; + cy.exec( + `oc patch oauths cluster --type json -p='[{ op: 'replace', path: '/spec/identityProviders', value: ${idpJSON}}]'`, + ); + }); + + // TODO: Add tests for HTPasswd and Request Header identity providers. + // These IDPs require file upload. + + it('creates a Basic Authentication IDP and shows the BasicAuth IDP on the OAuth settings page', () => { + const idpName = `basic-auth-${testName}`; + oauth.idpSetup(idpName, 'basicauth'); + cy.get('#url').type('https://example.com'); + oauth.idpSaveAndVerify(idpName, 'BasicAuth'); + }); + + it('creates a GitHub IDP and displays it on the OAuth settings page', () => { + const idpName = `github-${testName}`; + oauth.idpSetup(idpName, 'github'); + cy.get('#client-id').type('my-client-id'); + cy.get('#client-secret').type('my-client-secret'); + cy.get('[data-test-list-input-for="Organization"]').type('my-organization'); + oauth.idpSaveAndVerify(idpName, 'GitHub'); + }); + + it('creates a GitLab IDP and displays on the OAuth settings page', () => { + const idpName = `gitlab-${testName}`; + oauth.idpSetup(idpName, 'gitlab'); + cy.get('#url').type('https://example.com'); + cy.get('#client-id').type('my-client-id'); + cy.get('#client-secret').type('my-client-secret'); + oauth.idpSaveAndVerify(idpName, 'GitLab'); + }); + + it('creates a Google IDP and displays it on the OAuth settings page', () => { + const idpName = `google-${testName}`; + oauth.idpSetup(idpName, 'google'); + cy.get('#client-id').type('my-client-id'); + cy.get('#client-secret').type('my-client-secret'); + cy.get('#hosted-domain').type('example.com'); + oauth.idpSaveAndVerify(idpName, 'Google'); + }); + + it('creates a Keystone IDP and displays it on the OAuth settings page', () => { + const idpName = `keystone-${testName}`; + oauth.idpSetup(idpName, 'keystone'); + cy.get('#domain-name').type('example.com'); + cy.get('#url').type('https://example.com'); + oauth.idpSaveAndVerify(idpName, 'Keystone'); + }); + + it('creates a LDAP IDP and displays it on the OAuth settings page', () => { + const idpName = `ldap-${testName}`; + oauth.idpSetup(idpName, 'ldap'); + cy.get('#url').type('ldap://ldap.example.com/o=Acme?cn?sub?(enabled=true)'); + oauth.idpSaveAndVerify(idpName, 'LDAP'); + }); + + it('creates a OpenID IDP and displays it on the OAuth settings page', () => { + const idpName = `oidc-${testName}`; + oauth.idpSetup(idpName, 'oidconnect'); + cy.get('#client-id').type('my-client-id'); + cy.get('#client-secret').type('my-client-secret'); + cy.get('#issuer').type('https://example.com'); + oauth.idpSaveAndVerify(idpName, 'OpenID'); + }); +}); diff --git a/frontend/packages/integration-tests-cypress/tests/crud/environment.cy.ts b/frontend/packages/integration-tests-cypress/tests/crud/environment.cy.ts new file mode 100644 index 000000000000..b472a9aaba77 --- /dev/null +++ b/frontend/packages/integration-tests-cypress/tests/crud/environment.cy.ts @@ -0,0 +1,78 @@ +import { safeLoad, safeDump } from 'js-yaml'; +import * as _ from 'lodash'; +import { checkErrors, testName } from '../../support'; +import { detailsPage } from '../../views/details-page'; +import { environment } from '../../views/environment'; +import { errorMessage } from '../../views/form'; +import { listPage } from '../../views/list-page'; +import * as yamlEditor from '../../views/yaml-editor'; + +const WORKLOAD_NAME = `filter-${testName}`; + +describe('Interacting with the environment variable editor', () => { + before(() => { + cy.createProjectWithCLI(testName); + cy.visit(`/k8s/ns/${testName}/deployments`); + listPage.clickCreateYAMLbutton(); + cy.byTestID('yaml-view-input').click(); + yamlEditor.isLoaded(); + yamlEditor.getEditorContent().then((content) => { + const newContent = _.defaultsDeep( + {}, + { metadata: { name: WORKLOAD_NAME, labels: { 'lbl-env': testName } } }, + safeLoad(content), + ); + yamlEditor.setEditorContent(safeDump(newContent)).then(() => { + yamlEditor.clickSaveCreateButton(); + cy.get(errorMessage).should('not.exist'); + detailsPage.sectionHeaderShouldExist('Deployment details'); + }); + }); + cy.exec( + `oc create cm my-config --from-literal=cmk1=config1 --from-literal=cmk2=config2 -n ${testName}`, + ); + cy.exec( + `oc create secret generic my-secret --from-literal=key1=supersecret --from-literal=key2=topsecret -n ${testName}`, + ); + checkErrors(); + }); + + beforeEach(() => { + cy.visit(`/k8s/ns/${testName}/deployments/${WORKLOAD_NAME}/environment`); + }); + + afterEach(() => { + checkErrors(); + }); + + after(() => { + cy.deleteProjectWithCLI(testName); + }); + + it('When a variable is added or deleted it shows the correct variables', () => { + const key = 'KEY'; + const value = 'value'; + environment.addVariable(key, value); + environment.validateKeyAndValue(key, value, true); + environment.deleteVariable(); + environment.validateKeyAndValue(key, value, false); + }); + + it('When a variable is added or deleted from a config map it shows the correct variables', () => { + const resourceName = 'my-config'; + const prefix = 'testcm'; + environment.addVariableFrom(resourceName, prefix); + environment.validateValueFrom(resourceName, prefix, true); + environment.deleteFromVariable(); + environment.validateValueFrom(resourceName, prefix, false); + }); + + it('When a variable is added or deleted from a secret it shows the correct variables', () => { + const resourceName = 'my-secret'; + const prefix = 'testsecret'; + environment.addVariableFrom(resourceName, prefix); + environment.validateValueFrom(resourceName, prefix, true); + environment.deleteFromVariable(); + environment.validateValueFrom(resourceName, prefix, false); + }); +}); diff --git a/frontend/packages/integration-tests-cypress/views/environment.ts b/frontend/packages/integration-tests-cypress/views/environment.ts new file mode 100644 index 000000000000..674f77a2aefe --- /dev/null +++ b/frontend/packages/integration-tests-cypress/views/environment.ts @@ -0,0 +1,61 @@ +const saveBtn = '.environment-buttons .pf-m-primary'; +const option = '[role="option"]'; + +export const environment = { + isLoaded: () => { + cy.byTestID('pairs-list-name').should('exist'); + cy.get(saveBtn).should('be.enabled'); + }, + addVariable: (key: string, value: string) => { + environment.isLoaded(); + cy.byTestID('pairs-list-name').clear(); + cy.byTestID('pairs-list-name').type(key); + cy.byTestID('pairs-list-value').clear(); + cy.byTestID('pairs-list-value').type(value); + cy.get(saveBtn).click(); + }, + addVariableFrom: (resourceName: string, resourcePrefix?: string, getExactResource?: boolean) => { + environment.isLoaded(); + cy.get('.value-from .pf-c-dropdown__toggle') + .click() + .byLegacyTestID('dropdown-text-filter') + .type(resourceName); + if (getExactResource) { + cy.get(option).find('.co-resource-item__resource-name').contains(resourceName).click(); + } else { + cy.get(option).first().click(); + } + if (resourcePrefix) { + cy.byLegacyTestID('env-prefix').clear().type(resourcePrefix); + } + cy.get(saveBtn).click(); + }, + deleteVariable: () => { + environment.isLoaded(); + cy.byTestID('delete-button').first().click(); + cy.get(saveBtn).click(); + }, + deleteFromVariable: () => { + environment.isLoaded(); + cy.byLegacyTestID('pairs-list__delete-from-btn').click(); + cy.get(saveBtn).click(); + }, + validateKeyAndValue: (key: string, value: string, isPresent: boolean) => { + if (isPresent) { + cy.byTestID('pairs-list-name').should('have.value', key); + cy.byTestID('pairs-list-value').should('have.value', value); + } else { + cy.byTestID('pairs-list-name').should('not.have.value', key); + cy.byTestID('pairs-list-value').should('not.have.value', value); + } + }, + validateValueFrom: (valueFrom: string, prefix: string, isPresent: boolean) => { + if (isPresent) { + cy.get('.co-resource-item__resource-name').last().should('have.text', valueFrom); + cy.byLegacyTestID('env-prefix').should('have.value', prefix); + } else { + cy.get('.co-resource-item__resource-name').last().should('have.text', 'container'); + cy.byLegacyTestID('env-prefix').should('have.value', ''); + } + }, +}; diff --git a/frontend/packages/integration-tests-cypress/views/oauth.ts b/frontend/packages/integration-tests-cypress/views/oauth.ts new file mode 100644 index 000000000000..bfc991c2ce41 --- /dev/null +++ b/frontend/packages/integration-tests-cypress/views/oauth.ts @@ -0,0 +1,20 @@ +const idpNameInput = '#idp-name'; +const oauthSettingsURL = '/k8s/cluster/config.openshift.io~v1~OAuth/cluster'; + +export const oauth = { + idpSetup: (idpName: string, idpID: string) => { + cy.visit(oauthSettingsURL); + cy.byLegacyTestID('dropdown-button').click(); + cy.byLegacyTestID(idpID).click(); + cy.get(idpNameInput).clear(); + cy.get(idpNameInput).type(idpName); + }, + idpSaveAndVerify: (idpName: string, idpType: string) => { + cy.byLegacyTestID('add-idp').click(); + cy.get('.pf-c-alert.pf-m-danger').should('not.exist'); + cy.url().should('include', oauthSettingsURL); + cy.get(`[data-test-idp-name="${idpName}"]`).should('have.text', idpName); + cy.get(`[data-test-idp-type-for="${idpName}"]`).should('have.text', idpType); + cy.get(`[data-test-idp-mapping-for="${idpName}"]`).should('have.text', 'claim'); + }, +};