From cc7a315242fa63cc6236a870e5118816d42cd19b 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/alertmanager.scenario.ts | 519 ------------------ .../tests/cluster-settings.scenario.ts | 94 ---- .../tests/environment.scenario.ts | 187 ------- .../tests/monitoring.scenario.ts | 234 -------- .../integration-tests/tests/oauth.scenario.ts | 234 -------- .../tests/secrets.scenario.ts | 480 ---------------- .../views/cluster-settings.view.ts | 18 - .../views/monitoring.view.ts | 82 --- .../integration-tests/views/oauth.view.ts | 46 -- .../alertmanager/alertmanager.cy.ts | 109 ++++ .../alertmanager/receivers/email.cy.ts | 122 ++++ .../alertmanager/receivers/pagerduty.cy.ts | 161 ++++++ .../alertmanager/receivers/slack.cy.ts | 105 ++++ .../alertmanager/receivers/webhook.cy.ts | 67 +++ .../cluster-settings/cluster-settings.cy.ts | 68 +++ .../tests/cluster-settings/oauth.cy.ts | 85 +++ .../tests/crud/environment.cy.ts | 79 +++ .../tests/crud/secrets/add-to-workload.cy.ts | 116 ++++ .../tests/crud/secrets/image-pull.cy.ts | 148 +++++ .../key-value.cy.ts} | 30 +- .../tests/crud/secrets/source.cy.ts | 97 ++++ .../tests/crud/secrets/webhook.cy.ts | 56 ++ .../integration-tests-cypress/tsconfig.json | 8 +- .../views/alertmanager.ts | 90 +++ .../views/environment.ts | 61 ++ .../integration-tests-cypress/views/oauth.ts | 20 + .../integration-tests-cypress/views/secret.ts | 60 +- .../components/configmap-and-secret-data.tsx | 5 +- .../modals/add-secret-to-workload.tsx | 3 + .../alertmanager/alertmanager-config.tsx | 1 + .../alertmanager/alertmanager-page.tsx | 8 +- .../components/secrets/create-secret.tsx | 20 +- frontend/public/components/utils/headings.tsx | 1 + 33 files changed, 1491 insertions(+), 1923 deletions(-) delete mode 100644 frontend/integration-tests/tests/alertmanager.scenario.ts 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/monitoring.scenario.ts delete mode 100644 frontend/integration-tests/tests/oauth.scenario.ts delete mode 100644 frontend/integration-tests/tests/secrets.scenario.ts delete mode 100644 frontend/integration-tests/views/cluster-settings.view.ts delete mode 100644 frontend/integration-tests/views/monitoring.view.ts delete mode 100644 frontend/integration-tests/views/oauth.view.ts create mode 100644 frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/alertmanager.cy.ts create mode 100644 frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/receivers/email.cy.ts create mode 100644 frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/receivers/pagerduty.cy.ts create mode 100644 frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/receivers/slack.cy.ts create mode 100644 frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/receivers/webhook.cy.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/tests/crud/secrets/add-to-workload.cy.ts create mode 100644 frontend/packages/integration-tests-cypress/tests/crud/secrets/image-pull.cy.ts rename frontend/packages/integration-tests-cypress/tests/crud/{secrets.cy.ts => secrets/key-value.cy.ts} (85%) create mode 100644 frontend/packages/integration-tests-cypress/tests/crud/secrets/source.cy.ts create mode 100644 frontend/packages/integration-tests-cypress/tests/crud/secrets/webhook.cy.ts create mode 100644 frontend/packages/integration-tests-cypress/views/alertmanager.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/alertmanager.scenario.ts b/frontend/integration-tests/tests/alertmanager.scenario.ts deleted file mode 100644 index 02a0b0209ff2..000000000000 --- a/frontend/integration-tests/tests/alertmanager.scenario.ts +++ /dev/null @@ -1,519 +0,0 @@ -import { browser, ExpectedConditions as until } from 'protractor'; -import * as _ from 'lodash'; -import { safeLoad } from 'js-yaml'; - -import { checkLogs, checkErrors, firstElementByTestID, appHost } from '../protractor.conf'; -import { fillInput } from '@console/shared/src/test-utils/utils'; -import { dropdownMenuForTestID } from '../views/form.view'; -import { - AlertmanagerConfig, - AlertmanagerReceiver, -} from '@console/internal/components/monitoring/alertmanager/alertmanager-config'; -import * as crudView from '../views/crud.view'; -import * as yamlView from '../views/yaml.view'; -import * as monitoringView from '../views/monitoring.view'; -import * as horizontalnavView from '../views/horizontal-nav.view'; -import { execSync } from 'child_process'; - -const getGlobalsAndReceiverConfig = (configName: string, yamlStr: string) => { - const config: AlertmanagerConfig = safeLoad(yamlStr); - const receiverConfig: AlertmanagerReceiver = _.find(config.receivers, { name: 'MyReceiver' }); - return { - globals: config.global, - receiverConfig: receiverConfig[configName][0], - }; -}; - -describe('Alertmanager: PagerDuty Receiver Form', () => { - afterAll(() => { - execSync( - `kubectl patch secret 'alertmanager-main' -n 'openshift-monitoring' --type='json' -p='[{ op: 'replace', path: '/data/alertmanager.yaml', value: ${monitoringView.defaultAlertmanagerYaml}}]'`, - ); - }); - - afterEach(() => { - checkLogs(); - checkErrors(); - }); - - it('creates PagerDuty Receiver correctly', async () => { - await browser.get(`${appHost}/monitoring/alertmanagerconfig`); - await crudView.isLoaded(); - await firstElementByTestID('create-receiver').click(); - await crudView.isLoaded(); - await firstElementByTestID('receiver-name').sendKeys('MyReceiver'); - await firstElementByTestID('dropdown-button').click(); - await crudView.isLoaded(); - await dropdownMenuForTestID('pagerduty_configs').click(); - await crudView.isLoaded(); - await firstElementByTestID('integration-key').sendKeys(''); - await firstElementByTestID('label-name-0').sendKeys('severity'); - await firstElementByTestID('label-value-0').sendKeys('warning'); - - expect(firstElementByTestID('pagerduty-url').getAttribute('value')).toEqual( - 'https://events.pagerduty.com/v2/enqueue', - ); - - // adv config options - await monitoringView.showAdvancedConfiguration.click(); - expect(firstElementByTestID('send-resolved-alerts').getAttribute('checked')).toBeTruthy(); - expect(firstElementByTestID('pagerduty-client').getAttribute('value')).toEqual( - '{{ template "pagerduty.default.client" . }}', - ); - expect(firstElementByTestID('pagerduty-client-url').getAttribute('value')).toEqual( - '{{ template "pagerduty.default.clientURL" . }}', - ); - expect(firstElementByTestID('pagerduty-description').getAttribute('value')).toEqual( - '{{ template "pagerduty.default.description" .}}', - ); - expect(firstElementByTestID('pagerduty-severity').getAttribute('value')).toEqual('error'); - await monitoringView.saveButton.click(); - await crudView.isLoaded(); - await monitoringView.wait(until.elementToBeClickable(crudView.nameFilter)); - await crudView.nameFilter.clear(); - await crudView.nameFilter.sendKeys('MyReceiver'); - monitoringView.getFirstRowAsText().then((text) => { - expect(text).toEqual('MyReceiver pagerduty severity = warning'); - }); - }); - - it('saves globals correctly', async () => { - await browser.get(`${appHost}/monitoring/alertmanagerconfig/receivers/MyReceiver/edit`); - await browser.wait(until.presenceOf(firstElementByTestID('cancel'))); - - // monitoringView.saveAsDefault checkbox disabled when url equals global url - expect(monitoringView.saveAsDefault.isEnabled()).toBeFalsy(); - - // changing url, enables monitoringView.saveAsDefault unchecked, should save pagerduty_url with Receiver - await fillInput( - firstElementByTestID('pagerduty-url'), - 'http://pagerduty-url-specific-to-receiver', - ); - expect(monitoringView.saveAsDefault.isEnabled()).toBeTruthy(); - expect(monitoringView.saveAsDefault.getAttribute('checked')).toBeFalsy(); - await monitoringView.saveButton.click(); - await crudView.isLoaded(); - - //pagerduty_url should be saved with Receiver and not global - await horizontalnavView.clickHorizontalTab('YAML'); - await yamlView.isLoaded(); - let yamlStr = await yamlView.getEditorContent(); - let configs = getGlobalsAndReceiverConfig('pagerduty_configs', yamlStr); - expect(_.has(configs.globals, 'pagerduty_url')).toBeFalsy(); - expect(configs.receiverConfig.url).toBe('http://pagerduty-url-specific-to-receiver'); - - // save pagerduty_url as default/global - await browser.get(`${appHost}/monitoring/alertmanagerconfig/receivers/MyReceiver/edit`); - await browser.wait(until.presenceOf(firstElementByTestID('cancel'))); - await fillInput(firstElementByTestID('pagerduty-url'), 'http://global-pagerduty-url'); - await crudView.isLoaded(); - expect(monitoringView.saveAsDefault.isEnabled()).toBeTruthy(); - monitoringView.saveAsDefault.click(); - expect(monitoringView.saveAsDefault.getAttribute('checked')).toBeTruthy(); - await monitoringView.saveButton.click(); - await crudView.isLoaded(); - - // pagerduty_url should be saved as global, not with Receiver - await horizontalnavView.clickHorizontalTab('YAML'); - await yamlView.isLoaded(); - yamlStr = await yamlView.getEditorContent(); - configs = getGlobalsAndReceiverConfig('pagerduty_configs', yamlStr); - expect(configs.globals.pagerduty_url).toBe('http://global-pagerduty-url'); - expect(_.has(configs.receiverConfig, 'url')).toBeFalsy(); - - // save pagerduty url to receiver with an existing global - await browser.get(`${appHost}/monitoring/alertmanagerconfig/receivers/MyReceiver/edit`); - await browser.wait(until.presenceOf(firstElementByTestID('cancel'))); - await fillInput( - firstElementByTestID('pagerduty-url'), - 'http://pagerduty-url-specific-to-receiver', - ); - expect(monitoringView.saveAsDefault.isEnabled()).toBeTruthy(); - expect(monitoringView.saveAsDefault.getAttribute('checked')).toBeFalsy(); - await monitoringView.saveButton.click(); - await crudView.isLoaded(); - - // pagerduty_url should be saved with Receiver, as well as having a global pagerduty_url prop - await horizontalnavView.clickHorizontalTab('YAML'); - await yamlView.isLoaded(); - yamlStr = await yamlView.getEditorContent(); - configs = getGlobalsAndReceiverConfig('pagerduty_configs', yamlStr); - expect(configs.globals.pagerduty_url).toBe('http://global-pagerduty-url'); - expect(configs.receiverConfig.url).toBe('http://pagerduty-url-specific-to-receiver'); - }); - - it('saves advanced configuration fields correctly', async () => { - await browser.get(`${appHost}/monitoring/alertmanagerconfig/receivers/MyReceiver/edit`); - await browser.wait(until.presenceOf(firstElementByTestID('cancel'))); - - await monitoringView.showAdvancedConfiguration.click(); - - // change first 3 props so that they are diff from global values, thus saved to Receiver config - expect(monitoringView.sendResolvedAlerts.getAttribute('checked')).toBeTruthy(); - await monitoringView.sendResolvedAlerts.click(); - expect(monitoringView.sendResolvedAlerts.getAttribute('checked')).toBeFalsy(); - await fillInput(firstElementByTestID('pagerduty-client'), 'updated-client'); - await fillInput(firstElementByTestID('pagerduty-client-url'), 'http://updated-client-url'); - - await monitoringView.saveButton.click(); - await crudView.isLoaded(); - - // 3 changed fields should be saved with Receiver. description and severity should not be - // saved with Receiver since they equal global values - await horizontalnavView.clickHorizontalTab('YAML'); - await yamlView.isLoaded(); - let yamlStr = await yamlView.getEditorContent(); - let configs = getGlobalsAndReceiverConfig('pagerduty_configs', yamlStr); - expect(configs.receiverConfig.send_resolved).toBeFalsy(); - expect(configs.receiverConfig.client).toBe('updated-client'); - expect(configs.receiverConfig.client_url).toBe('http://updated-client-url'); - expect(configs.receiverConfig.description).toBe(undefined); - expect(configs.receiverConfig.severity).toBe(undefined); - - // restore default values for the 3, change desc and severity -which should then be saved - // with Receiver while initial 3 are removed from Receiver config - await browser.get(`${appHost}/monitoring/alertmanagerconfig/receivers/MyReceiver/edit`); - await browser.wait(until.presenceOf(firstElementByTestID('cancel'))); - await monitoringView.showAdvancedConfiguration.click(); - expect(monitoringView.sendResolvedAlerts.getAttribute('checked')).toBeFalsy(); - await monitoringView.sendResolvedAlerts.click(); - expect(monitoringView.sendResolvedAlerts.getAttribute('checked')).toBeTruthy(); - await fillInput( - firstElementByTestID('pagerduty-client'), - '{{ template "pagerduty.default.client" . }}', - ); - await fillInput( - firstElementByTestID('pagerduty-client-url'), - '{{ template "pagerduty.default.clientURL" . }}', - ); - await fillInput(firstElementByTestID('pagerduty-description'), 'new description'); - await fillInput(firstElementByTestID('pagerduty-severity'), 'warning'); - await monitoringView.saveButton.click(); - await crudView.isLoaded(); - - await horizontalnavView.clickHorizontalTab('YAML'); - await yamlView.isLoaded(); - yamlStr = await yamlView.getEditorContent(); - configs = getGlobalsAndReceiverConfig('pagerduty_configs', yamlStr); - expect(configs.receiverConfig.send_resolved).toBe(undefined); - expect(configs.receiverConfig.client).toBe(undefined); - expect(configs.receiverConfig.client_url).toBe(undefined); - expect(configs.receiverConfig.description).toBe('new description'); - expect(configs.receiverConfig.severity).toBe('warning'); - }); -}); - -describe('Alertmanager: Email Receiver Form', () => { - afterAll(() => { - execSync( - `kubectl patch secret 'alertmanager-main' -n 'openshift-monitoring' --type='json' -p='[{ op: 'replace', path: '/data/alertmanager.yaml', value: ${monitoringView.defaultAlertmanagerYaml}}]'`, - ); - }); - - afterEach(() => { - checkLogs(); - checkErrors(); - }); - - it('creates Email Receiver correctly', async () => { - await browser.get(`${appHost}/monitoring/alertmanagerconfig`); - await crudView.isLoaded(); - await firstElementByTestID('create-receiver').click(); - await crudView.isLoaded(); - await fillInput(firstElementByTestID('receiver-name'), 'MyReceiver'); - await firstElementByTestID('dropdown-button').click(); - await crudView.isLoaded(); - await dropdownMenuForTestID('email_configs').click(); - await crudView.isLoaded(); - - // check defaults - expect(monitoringView.saveAsDefault.isEnabled()).toBeFalsy(); // prior to smtp change, monitoringView.saveAsDefault disabled - expect(firstElementByTestID('email-hello').getAttribute('value')).toEqual('localhost'); - expect(firstElementByTestID('email-require-tls').getAttribute('checked')).toBeTruthy(); - // adv fields - await monitoringView.showAdvancedConfiguration.click(); - expect(monitoringView.sendResolvedAlerts.getAttribute('checked')).toBeFalsy(); - expect(firstElementByTestID('email-html').getAttribute('value')).toEqual( - '{{ template "email.default.html" . }}', - ); - - // change required fields - await fillInput(firstElementByTestID('email-to'), 'you@there.com'); - await fillInput(firstElementByTestID('email-from'), 'me@here.com'); - expect(monitoringView.saveAsDefault.isEnabled()).toBeTruthy(); // monitoringView.saveAsDefault enabled - await fillInput(firstElementByTestID('email-smarthost'), 'smarthost:8080'); - await fillInput(firstElementByTestID('label-name-0'), 'severity'); - await fillInput(firstElementByTestID('label-value-0'), 'warning'); - await monitoringView.saveButton.click(); - await crudView.isLoaded(); - - // all required fields should be saved with Receiver and not globally - await horizontalnavView.clickHorizontalTab('YAML'); - await yamlView.isLoaded(); - const yamlStr = await yamlView.getEditorContent(); - const configs = getGlobalsAndReceiverConfig('email_configs', yamlStr); - expect(_.has(configs.globals, 'email_to')).toBeFalsy(); - expect(_.has(configs.globals, 'smtp_from')).toBeFalsy(); - expect(_.has(configs.globals, 'smtp_smarthost')).toBeFalsy(); - expect(_.has(configs.globals, 'smtp_require_tls')).toBeFalsy(); - expect(configs.receiverConfig.to).toBe('you@there.com'); - expect(configs.receiverConfig.from).toBe('me@here.com'); - expect(configs.receiverConfig.smarthost).toBe('smarthost:8080'); - expect(_.has(configs.receiverConfig, 'require_tls')).toBeFalsy(); // unchanged from global value - }); - - it('saves globals and advanced fields correctly', async () => { - await browser.get(`${appHost}/monitoring/alertmanagerconfig/receivers/MyReceiver/edit`); - await browser.wait(until.presenceOf(firstElementByTestID('cancel'))); - - // Check updated form fields - expect(firstElementByTestID('email-to').getAttribute('value')).toEqual('you@there.com'); - expect(monitoringView.saveAsDefault.isEnabled()).toBeTruthy(); // smtp_from different from global - expect(monitoringView.saveAsDefault.getAttribute('checked')).toBeFalsy(); - expect(firstElementByTestID('email-from').getAttribute('value')).toEqual('me@here.com'); - expect(firstElementByTestID('email-hello').getAttribute('value')).toEqual('localhost'); - - // Change smtp global fields - await fillInput(firstElementByTestID('email-auth-username'), 'username'); - await fillInput(firstElementByTestID('email-auth-password'), 'password'); - await fillInput(firstElementByTestID('email-auth-identity'), 'identity'); - await fillInput(firstElementByTestID('email-auth-secret'), 'secret'); - await firstElementByTestID('email-require-tls').click(); - - // Change advanced fields - await monitoringView.showAdvancedConfiguration.click(); - await monitoringView.sendResolvedAlerts.click(); - await fillInput(firstElementByTestID('email-html'), 'myhtml'); - await monitoringView.saveButton.click(); // monitoringView.saveAsDefault not checked, so all should be saved with Reciever - await crudView.isLoaded(); - - // all fields saved to receiver since save as default not checked - await horizontalnavView.clickHorizontalTab('YAML'); - await yamlView.isLoaded(); - - let yamlStr = await yamlView.getEditorContent(); - let configs = getGlobalsAndReceiverConfig('email_configs', yamlStr); - expect(_.has(configs.globals, 'smtp_auth_username')).toBeFalsy(); - expect(configs.receiverConfig.auth_username).toBe('username'); - expect(configs.receiverConfig.auth_password).toBe('password'); - expect(configs.receiverConfig.auth_identity).toBe('identity'); - expect(configs.receiverConfig.auth_secret).toBe('secret'); - expect(configs.receiverConfig.require_tls).toBeFalsy(); - // adv fields - expect(configs.receiverConfig.send_resolved).toBeTruthy(); - expect(configs.receiverConfig.html).toBe('myhtml'); - - // Save As Default - await browser.get(`${appHost}/monitoring/alertmanagerconfig/receivers/MyReceiver/edit`); - await browser.wait(until.presenceOf(firstElementByTestID('cancel'))); - monitoringView.saveAsDefault.click(); - await monitoringView.saveButton.click(); - await crudView.isLoaded(); - // global fields saved in config.global - await horizontalnavView.clickHorizontalTab('YAML'); - await yamlView.isLoaded(); - yamlStr = await yamlView.getEditorContent(); - configs = getGlobalsAndReceiverConfig('email_configs', yamlStr); - expect(configs.globals.smtp_from).toBe('me@here.com'); - expect(configs.globals.smtp_hello).toBe('localhost'); - expect(configs.globals.smtp_smarthost).toBe('smarthost:8080'); - expect(configs.globals.smtp_auth_username).toBe('username'); - expect(configs.globals.smtp_auth_password).toBe('password'); - expect(configs.globals.smtp_auth_identity).toBe('identity'); - expect(configs.globals.smtp_auth_secret).toBe('secret'); - expect(configs.globals.smtp_require_tls).toBeFalsy(); - // non-global fields should still be saved with Receiver - expect(configs.receiverConfig.to).toBe('you@there.com'); - }); -}); - -describe('Alertmanager: Slack Receiver Form', () => { - afterAll(() => { - execSync( - `kubectl patch secret 'alertmanager-main' -n 'openshift-monitoring' --type='json' -p='[{ op: 'replace', path: '/data/alertmanager.yaml', value: ${monitoringView.defaultAlertmanagerYaml}}]'`, - ); - }); - - afterEach(() => { - checkLogs(); - checkErrors(); - }); - - it('creates Slack Receiver correctly', async () => { - await browser.get(`${appHost}/monitoring/alertmanagerconfig`); - await crudView.isLoaded(); - await firstElementByTestID('create-receiver').click(); - await crudView.isLoaded(); - await fillInput(firstElementByTestID('receiver-name'), 'MyReceiver'); - await firstElementByTestID('dropdown-button').click(); - await crudView.isLoaded(); - await dropdownMenuForTestID('slack_configs').click(); - await crudView.isLoaded(); - - // check defaults - expect(monitoringView.saveAsDefault.isEnabled()).toBeFalsy(); - // adv fields - await monitoringView.showAdvancedConfiguration.click(); - expect(monitoringView.sendResolvedAlerts.getAttribute('checked')).toBeFalsy(); - expect(firstElementByTestID('slack-icon-url').getAttribute('value')).toEqual( - '{{ template "slack.default.iconurl" .}}', - ); - expect(firstElementByTestID('slack-icon-emoji').isPresent()).toBe(false); - await firstElementByTestID('slack-icon-type-emoji').click(); - expect(firstElementByTestID('slack-icon-url').isPresent()).toBe(false); - expect(firstElementByTestID('slack-icon-emoji').getAttribute('value')).toEqual( - '{{ template "slack.default.iconemoji" .}}', - ); - expect(firstElementByTestID('slack-username').getAttribute('value')).toEqual( - '{{ template "slack.default.username" . }}', - ); - expect(firstElementByTestID('slack-link-names').getAttribute('checked')).toBeFalsy(); - - // change required fields - await fillInput(firstElementByTestID('slack-api-url'), 'http://myslackapi'); - expect(monitoringView.saveAsDefault.isEnabled()).toBeTruthy(); // monitoringView.saveAsDefault enabled - await fillInput(firstElementByTestID('slack-channel'), 'myslackchannel'); - await fillInput(firstElementByTestID('label-name-0'), 'severity'); - await fillInput(firstElementByTestID('label-value-0'), 'warning'); - await monitoringView.saveButton.click(); - await crudView.isLoaded(); - - // all required fields should be saved with Receiver and not globally - await horizontalnavView.clickHorizontalTab('YAML'); - await yamlView.isLoaded(); - const yamlStr = await yamlView.getEditorContent(); - const configs = getGlobalsAndReceiverConfig('slack_configs', yamlStr); - expect(_.has(configs.globals, 'slack_api_url')).toBeFalsy(); - expect(configs.receiverConfig.channel).toBe('myslackchannel'); - expect(configs.receiverConfig.api_url).toBe('http://myslackapi'); - // make sure adv fields are not saved since they equal their global values - expect(_.has(configs.receiverConfig, 'send_resolved')).toBeFalsy(); - expect(_.has(configs.receiverConfig, 'username')).toBeFalsy(); - }); - - it('saves globals and advanced fields correctly', async () => { - await browser.get(`${appHost}/monitoring/alertmanagerconfig/receivers/MyReceiver/edit`); - await browser.wait(until.presenceOf(firstElementByTestID('cancel'))); - - // Check updated form fields - expect(firstElementByTestID('slack-channel').getAttribute('value')).toEqual('myslackchannel'); - expect(monitoringView.saveAsDefault.isEnabled()).toBeTruthy(); // different from global - expect(firstElementByTestID('slack-api-url').getAttribute('value')).toEqual( - 'http://myslackapi', - ); - - // Change advanced fields - await monitoringView.showAdvancedConfiguration.click(); - await monitoringView.sendResolvedAlerts.click(); - await fillInput(firstElementByTestID('slack-icon-url'), 'http://myslackicon'); - await fillInput(firstElementByTestID('slack-username'), 'slackuser'); - await firstElementByTestID('slack-link-names').click(); - - monitoringView.saveAsDefault.click(); - await monitoringView.saveButton.click(); - await crudView.isLoaded(); - await browser.get(`${appHost}/monitoring/alertmanagerconfig/receivers/MyReceiver/edit`); - await crudView.isLoaded(); - // check updated advanced form fields - await monitoringView.showAdvancedConfiguration.click(); - expect(monitoringView.sendResolvedAlerts.getAttribute('checked')).toBeTruthy(); - expect(firstElementByTestID('slack-icon-url').getAttribute('value')).toEqual( - 'http://myslackicon', - ); - expect(firstElementByTestID('slack-icon-emoji').isPresent()).toBe(false); - expect(firstElementByTestID('slack-username').getAttribute('value')).toEqual('slackuser'); - expect(firstElementByTestID('slack-link-names').getAttribute('checked')).toBeTruthy(); - - // check saved to slack receiver config yaml - await browser.get(`${appHost}/monitoring/alertmanageryaml`); - await yamlView.isLoaded(); - const yamlStr = await yamlView.getEditorContent(); - const configs = getGlobalsAndReceiverConfig('slack_configs', yamlStr); - expect(configs.globals.slack_api_url).toBe('http://myslackapi'); - expect(_.has(configs.receiverConfig, 'api_url')).toBeFalsy(); - expect(configs.receiverConfig.channel).toBe('myslackchannel'); - // advanced fields - expect(configs.receiverConfig.send_resolved).toBeTruthy(); - expect(configs.receiverConfig.icon_url).toBe('http://myslackicon'); - expect(configs.receiverConfig.username).toBe('slackuser'); - expect(configs.receiverConfig.link_names).toBeTruthy(); - }); -}); - -describe('Alertmanager: Webhook Receiver Form', () => { - afterAll(() => { - execSync( - `kubectl patch secret 'alertmanager-main' -n 'openshift-monitoring' --type='json' -p='[{ op: 'replace', path: '/data/alertmanager.yaml', value: ${monitoringView.defaultAlertmanagerYaml}}]'`, - ); - }); - - afterEach(() => { - checkLogs(); - checkErrors(); - }); - - it('creates Webhook Receiver correctly', async () => { - await browser.get(`${appHost}/monitoring/alertmanagerconfig`); - await crudView.isLoaded(); - await firstElementByTestID('create-receiver').click(); - await crudView.isLoaded(); - await fillInput(firstElementByTestID('receiver-name'), 'MyReceiver'); - await firstElementByTestID('dropdown-button').click(); - await crudView.isLoaded(); - await dropdownMenuForTestID('webhook_configs').click(); - await crudView.isLoaded(); - - // check adv field default value - await monitoringView.showAdvancedConfiguration.click(); - expect(monitoringView.sendResolvedAlerts.getAttribute('checked')).toBeTruthy(); - - // change required fields - await fillInput(firstElementByTestID('webhook-url'), 'http://mywebhookurl'); - await fillInput(firstElementByTestID('label-name-0'), 'severity'); - await fillInput(firstElementByTestID('label-value-0'), 'warning'); - await monitoringView.saveButton.click(); - await crudView.isLoaded(); - - // all required fields should be saved with Receiver - await horizontalnavView.clickHorizontalTab('YAML'); - await yamlView.isLoaded(); - const yamlStr = await yamlView.getEditorContent(); - const configs = getGlobalsAndReceiverConfig('webhook_configs', yamlStr); - expect(configs.receiverConfig.url).toBe('http://mywebhookurl'); - expect(_.has(configs.receiverConfig, 'send_resolved')).toBeFalsy(); - }); - - it('edits Webhook Receiver and saves advanced fields correctly', async () => { - await browser.get(`${appHost}/monitoring/alertmanagerconfig/receivers/MyReceiver/edit`); - await browser.wait(until.presenceOf(firstElementByTestID('cancel'))); - - // Check updated form fields - expect(firstElementByTestID('webhook-url').getAttribute('value')).toEqual( - 'http://mywebhookurl', - ); - - await fillInput(firstElementByTestID('webhook-url'), 'http://myupdatedwebhookurl'); - // Change advanced fields - await monitoringView.showAdvancedConfiguration.click(); - await monitoringView.sendResolvedAlerts.click(); - - await monitoringView.saveButton.click(); - await crudView.isLoaded(); - await browser.get(`${appHost}/monitoring/alertmanagerconfig/receivers/MyReceiver/edit`); - await crudView.isLoaded(); - // check updated advanced form fields - await monitoringView.showAdvancedConfiguration.click(); - expect(monitoringView.sendResolvedAlerts.getAttribute('checked')).toBeFalsy(); - - // check saved to slack receiver config yaml - await browser.get(`${appHost}/monitoring/alertmanageryaml`); - await yamlView.isLoaded(); - await horizontalnavView.clickHorizontalTab('YAML'); - await yamlView.isLoaded(); - const yamlStr = await yamlView.getEditorContent(); - const configs = getGlobalsAndReceiverConfig('webhook_configs', yamlStr); - expect(configs.receiverConfig.url).toBe('http://myupdatedwebhookurl'); - // advanced field - expect(configs.receiverConfig.send_resolved).toBeFalsy(); - }); -}); 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/monitoring.scenario.ts b/frontend/integration-tests/tests/monitoring.scenario.ts deleted file mode 100644 index da6121d0b246..000000000000 --- a/frontend/integration-tests/tests/monitoring.scenario.ts +++ /dev/null @@ -1,234 +0,0 @@ -import { browser, ExpectedConditions as until } from 'protractor'; - -import { checkLogs, checkErrors, firstElementByTestID, appHost } from '../protractor.conf'; -import { dropdownMenuForTestID } from '../views/form.view'; -import * as crudView from '../views/crud.view'; -import * as yamlView from '../views/yaml.view'; -import * as monitoringView from '../views/monitoring.view'; -import * as sidenavView from '../views/sidenav.view'; -import * as horizontalnavView from '../views/horizontal-nav.view'; -import { execSync } from 'child_process'; - -describe('Alertmanager: YAML', () => { - afterEach(() => { - checkLogs(); - checkErrors(); - }); - - it('displays the Alertmanager YAML page', async () => { - await sidenavView.clickNavLink(['Administration', 'Cluster Settings']); - await crudView.isLoaded(); - await horizontalnavView.clickHorizontalTab('Configuration'); - await crudView.isLoaded(); - await monitoringView.wait(until.elementToBeClickable(firstElementByTestID('Alertmanager'))); - expect(firstElementByTestID('Alertmanager').getText()).toContain('Alertmanager'); - await firstElementByTestID('Alertmanager').click(); - await crudView.isLoaded(); - await horizontalnavView.clickHorizontalTab('YAML'); - await yamlView.isLoaded(); - expect(yamlView.yamlEditor.isPresent()).toBe(true); - }); - - it('saves Alertmanager YAML', async () => { - expect(monitoringView.successAlert.isPresent()).toBe(false); - await yamlView.saveButton.click(); - await yamlView.isLoaded(); - expect(monitoringView.successAlert.isPresent()).toBe(true); - }); -}); - -describe('Alertmanager: Configuration', () => { - afterAll(() => { - execSync( - `kubectl patch secret 'alertmanager-main' -n 'openshift-monitoring' --type='json' -p='[{ op: 'replace', path: '/data/alertmanager.yaml', value: ${monitoringView.defaultAlertmanagerYaml}}]'`, - ); - }); - - afterEach(() => { - checkLogs(); - checkErrors(); - }); - - it('displays the Alertmanager Configuration Details page', async () => { - await browser.get(`${appHost}/monitoring/alertmanagerconfig`); - await crudView.isLoaded(); - expect(monitoringView.alertRoutingHeader.getText()).toContain('Alert routing'); - }); - - it('launches Alert Routing modal, edits and saves correctly', async () => { - await crudView.isLoaded(); - expect(monitoringView.alertRoutingEditButton.isPresent()).toBe(true); - await monitoringView.alertRoutingEditButton.click(); - await crudView.isLoaded(); - - await browser.wait(until.elementToBeClickable(firstElementByTestID('input-group-by'))); - await firstElementByTestID('input-group-by').sendKeys(', cluster'); - await firstElementByTestID('input-group-wait').clear(); - await firstElementByTestID('input-group-wait').sendKeys('60s'); - await firstElementByTestID('input-group-interval').clear(); - await firstElementByTestID('input-group-interval').sendKeys('10m'); - await firstElementByTestID('input-repeat-interval').clear(); - await firstElementByTestID('input-repeat-interval').sendKeys('24h'); - - await monitoringView.saveButton.click(); - await crudView.isLoaded(); - expect(firstElementByTestID('group_by_value').getText()).toContain(', cluster'); - expect(firstElementByTestID('group_wait_value').getText()).toEqual('60s'); - expect(firstElementByTestID('group_interval_value').getText()).toEqual('10m'); - expect(firstElementByTestID('repeat_interval_value').getText()).toEqual('24h'); - }); - - it('creates a receiver correctly', async () => { - await crudView.isLoaded(); - await firstElementByTestID('create-receiver').click(); - await crudView.isLoaded(); - - // these are hidden and disabled until receiverType selected - expect(firstElementByTestID('pagerduty-receiver-form').isPresent()).toBe(false); - expect(firstElementByTestID('receiver-routing-labels-editor').isPresent()).toBe(false); - expect(monitoringView.saveButton.isEnabled()).toBe(false); - - await firstElementByTestID('receiver-name').sendKeys('MyReceiver'); - await firstElementByTestID('dropdown-button').click(); - await crudView.isLoaded(); - - await dropdownMenuForTestID('pagerduty_configs').click(); - await crudView.isLoaded(); - - // these should be shown after receiverType selected - expect(firstElementByTestID('pagerduty-receiver-form').isPresent()).toBe(true); - expect(firstElementByTestID('receiver-routing-labels-editor').isPresent()).toBe(true); - - expect(firstElementByTestID('pagerduty-key-label').getText()).toEqual('Routing key'); - await firstElementByTestID('integration-type-prometheus').click(); - expect(firstElementByTestID('pagerduty-key-label').getText()).toEqual('Service key'); - - // pagerduty subform should still be invalid at this point, thus save button should be disabled - expect(monitoringView.saveButton.isEnabled()).toBe(false); - await firstElementByTestID('integration-key').sendKeys(''); - - // labels - expect(firstElementByTestID('invalid-label-name-error').isPresent()).toBe(false); - await firstElementByTestID('label-name-0').sendKeys('9abcgo'); // invalid, cannot start with digit - expect(firstElementByTestID('invalid-label-name-error').isPresent()).toBe(true); - await firstElementByTestID('label-name-0').clear(); - await firstElementByTestID('label-name-0').sendKeys('_abcd'); // valid, can start with and contain '_' - expect(firstElementByTestID('invalid-label-name-error').isPresent()).toBe(false); - await firstElementByTestID('label-name-0').clear(); - await firstElementByTestID('label-name-0').sendKeys('abcd@#$R@T%'); // invalid chars - expect(firstElementByTestID('invalid-label-name-error').isPresent()).toBe(true); - await firstElementByTestID('label-name-0').clear(); - expect(firstElementByTestID('duplicate-label-name-error').isPresent()).toBe(false); - await firstElementByTestID('label-name-0').sendKeys('severity'); - expect(firstElementByTestID('invalid-label-name-error').isPresent()).toBe(false); - await firstElementByTestID('label-value-0').sendKeys('warning'); - await firstElementByTestID('add-routing-label').click(); - await firstElementByTestID('label-name-1').sendKeys('severity'); - await firstElementByTestID('label-value-1').sendKeys('warning'); - expect(firstElementByTestID('duplicate-label-name-error').isPresent()).toBe(true); - await firstElementByTestID('remove-routing-label').click(); - expect(firstElementByTestID('duplicate-label-name-error').isPresent()).toBe(false); - - expect(monitoringView.saveButton.isEnabled()).toBe(true); // subform valid & labels provided, save should be enabled at this point - await monitoringView.saveButton.click(); - await crudView.isLoaded(); - await monitoringView.wait(until.elementToBeClickable(crudView.nameFilter)); - await crudView.nameFilter.clear(); - await crudView.nameFilter.sendKeys('MyReceiver'); - monitoringView.getFirstRowAsText().then((text) => { - expect(text).toEqual('MyReceiver pagerduty severity = warning'); - }); - }); - - it('edits a receiver correctly', async () => { - await crudView.isLoaded(); - await monitoringView.wait(until.elementToBeClickable(crudView.nameFilter)); - await crudView.nameFilter.clear(); - await crudView.nameFilter.sendKeys('MyReceiver'); - expect(crudView.resourceRows.count()).toBe(1); - await monitoringView.clickFirstRowKebabAction('Edit Receiver'); - await browser.wait(until.presenceOf(firstElementByTestID('cancel'))); - expect(firstElementByTestID('receiver-name').getAttribute('value')).toEqual('MyReceiver'); - expect(firstElementByTestID('dropdown-button').getText()).toEqual('PagerDuty'); - expect(firstElementByTestID('pagerduty-key-label').getText()).toEqual('Service key'); - expect(firstElementByTestID('integration-key').getAttribute('value')).toEqual( - '', - ); - expect(firstElementByTestID('label-name-0').getAttribute('value')).toEqual('severity'); - expect(firstElementByTestID('label-value-0').getAttribute('value')).toEqual('warning'); - - // Edit Values - - await firstElementByTestID('receiver-name').clear(); - await firstElementByTestID('receiver-name').sendKeys('MyEditedReceiver'); - await firstElementByTestID('label-name-0').clear(); - await firstElementByTestID('label-name-0').sendKeys('cluster'); - await firstElementByTestID('label-value-0').clear(); - await firstElementByTestID('label-value-0').sendKeys('MyCluster'); - - await monitoringView.saveButton.click(); - await crudView.isLoaded(); - await monitoringView.wait(until.elementToBeClickable(crudView.nameFilter)); - await crudView.nameFilter.clear(); - await crudView.nameFilter.sendKeys('MyEditedReceiver'); - monitoringView.getFirstRowAsText().then((text) => { - expect(text).toEqual('MyEditedReceiver pagerduty cluster = MyCluster'); - }); - }); - - it('deletes a receiver correctly', async () => { - await horizontalnavView.clickHorizontalTab('Details'); - await crudView.isLoaded(); - await monitoringView.wait(until.elementToBeClickable(crudView.nameFilter)); - await crudView.nameFilter.clear(); - await crudView.nameFilter.sendKeys('MyEditedReceiver'); - expect(crudView.resourceRows.count()).toBe(1); - - await monitoringView.clickFirstRowKebabAction('Delete Receiver'); - await browser.wait(until.presenceOf(monitoringView.saveButton)); - await monitoringView.saveButton.click(); - - await crudView.isLoaded(); - await monitoringView.wait(until.elementToBeClickable(crudView.nameFilter)); - await crudView.nameFilter.clear(); - await crudView.nameFilter.sendKeys('MyEditedReceiver'); - expect(crudView.resourceRows.count()).toBe(0); - }); - - it('prevents deletion of default receiver', async () => { - await crudView.isLoaded(); - await monitoringView.wait(until.elementToBeClickable(crudView.nameFilter)); - await crudView.nameFilter.clear(); - await crudView.nameFilter.sendKeys('Default'); - await monitoringView.openFirstRowKebabMenu(); - expect(monitoringView.disabledDeleteReceiverMenuItem.isPresent()).toBe(true); - }); - - it('prevents deletion and form edit of a receiver with sub-route', async () => { - // add receiver with sub-route - const yaml = `route: - routes: - - match: - service: database - receiver: team-DB-pager - routes: - - match: - owner: team-X - receiver: team-X-pager -receivers: -- name: 'team-X-pager' -- name: 'team-DB-pager'`; - await crudView.isLoaded(); - await horizontalnavView.clickHorizontalTab('YAML'); - await yamlView.isLoaded(); - await yamlView.setEditorContent(yaml); - await yamlView.saveButton.click(); - await yamlView.isLoaded(); - expect(monitoringView.successAlert.isPresent()).toBe(true); - - await horizontalnavView.clickHorizontalTab('Details'); - await monitoringView.openFirstRowKebabMenu(); - expect(monitoringView.disabledDeleteReceiverMenuItem.isPresent()).toBe(true); - expect(crudView.actionForLabel('Edit Receiver').isPresent()).toBe(true); - }); -}); 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/tests/secrets.scenario.ts b/frontend/integration-tests/tests/secrets.scenario.ts deleted file mode 100644 index 353cf32aab26..000000000000 --- a/frontend/integration-tests/tests/secrets.scenario.ts +++ /dev/null @@ -1,480 +0,0 @@ -/* eslint-disable max-nested-callbacks */ -import { $, $$, element, browser, by, ExpectedConditions as until } from 'protractor'; -import { execSync } from 'child_process'; - -import { appHost, testName, checkLogs, checkErrors, waitForCount } from '../protractor.conf'; -import * as crudView from '../views/crud.view'; -import * as secretsView from '../views/secrets.view'; -import { DeploymentKind } from '../../public/module/k8s'; - -describe('Interacting with the create secret forms', () => { - afterEach(() => { - checkLogs(); - checkErrors(); - }); - - describe('Webhook secret', () => { - const webhookSecretName = 'webhook-secret'; - const webhookSecretValue = 'webhookValue'; - - beforeAll(async () => secretsView.visitSecretsPage(appHost, testName)); - - it('creates webhook secret', async () => { - await secretsView.createSecret( - secretsView.createWebhookSecretLink, - testName, - webhookSecretName, - async () => { - await secretsView.secretWebhookInput.sendKeys(webhookSecretValue); - }, - ); - }); - - it('check for created webhook secret value', async () => { - await secretsView.checkSecret(testName, webhookSecretName, { - WebHookSecretKey: webhookSecretValue, - }); - }); - - it('edits webhook secret', async () => { - await secretsView.editSecret(testName, webhookSecretName, async () => { - await element(by.buttonText('Generate')).isPresent(); - await element(by.buttonText('Generate')).click(); - }); - }); - - it('check for edited webhook secret value', async () => { - await browser.wait( - until.textToBePresentInElement($('.co-m-pane__heading'), webhookSecretName), - ); - await secretsView.clickRevealValues(); - expect(secretsView.pre.get(0).getText()).not.toEqual(webhookSecretValue); - }); - - it('deletes the webhook secret', async () => { - await crudView.deleteResource('secrets', 'Secret', webhookSecretName); - }); - }); - - describe('Basic source secrets', () => { - const basicSourceSecretName = 'basic-source-secret'; - const basicSourceSecretUsername = 'username'; - const basicSourceSecretUsernameUpdated = 'usernameUpdated'; - const basicSourceSecretPassword = 'password'; - const basicSourceSecretPasswordUpdated = 'passwordUpdated'; - - beforeAll(async () => secretsView.visitSecretsPage(appHost, testName)); - - it('creates basic source secret', async () => { - await secretsView.createSecret( - secretsView.createSourceSecretLink, - testName, - basicSourceSecretName, - async () => { - await secretsView.secretUsernameInput.sendKeys(basicSourceSecretUsername); - await secretsView.secretPasswordInput.sendKeys(basicSourceSecretPassword); - }, - ); - }); - - it('check for created basic source secret values', async () => { - await secretsView.checkSecret(testName, basicSourceSecretName, { - username: basicSourceSecretUsername, - password: basicSourceSecretPassword, - }); - }); - - it('edits basic source secret', async () => { - await secretsView.editSecret(testName, basicSourceSecretName, async () => { - await secretsView.secretUsernameInput.clear(); - await secretsView.secretUsernameInput.sendKeys(basicSourceSecretUsernameUpdated); - await secretsView.secretPasswordInput.clear(); - await secretsView.secretPasswordInput.sendKeys(basicSourceSecretPasswordUpdated); - }); - }); - - it('check for edited basic source secret values', async () => { - await secretsView.checkSecret(testName, basicSourceSecretName, { - username: basicSourceSecretUsernameUpdated, - password: basicSourceSecretPasswordUpdated, - }); - }); - - it('deletes the basic source secret', async () => { - await crudView.deleteResource('secrets', 'Secret', basicSourceSecretName); - }); - }); - - describe('SSH source secrets', () => { - const sshSourceSecretName = 'ssh-source-secret'; - const sshSourceSecretSSHKey = 'sshKey'; - const sshSourceSecretSSHKeUpdated = 'sshKeyUpdated'; - - beforeAll(async () => secretsView.visitSecretsPage(appHost, testName)); - - it('creates SSH source secret', async () => { - await secretsView.createSecret( - secretsView.createSourceSecretLink, - testName, - sshSourceSecretName, - async () => { - await secretsView.authTypeDropdown.click(); - await secretsView.authSSHOption.click(); - await browser.wait(until.presenceOf(secretsView.uploadFileTextArea)); - await secretsView.uploadFileTextArea.sendKeys(sshSourceSecretSSHKey); - }, - ); - }); - - it('check for created SSH source secret values', async () => { - await secretsView.checkSecret(testName, sshSourceSecretName, { - 'ssh-privatekey': sshSourceSecretSSHKey, - }); - }); - - it('edits SSH source secret', async () => { - await secretsView.editSecret(testName, sshSourceSecretName, async () => { - await secretsView.uploadFileTextArea.clear(); - await secretsView.uploadFileTextArea.sendKeys(sshSourceSecretSSHKeUpdated); - }); - }); - - it('check for edited SSH source secret values', async () => { - await secretsView.checkSecret(testName, sshSourceSecretName, { - 'ssh-privatekey': sshSourceSecretSSHKeUpdated, - }); - }); - - it('deletes the SSH source secret', async () => { - await crudView.deleteResource('secrets', 'Secret', sshSourceSecretName); - }); - }); - - describe('Registry credentials image secrets', () => { - const credentialsImageSecretName = 'registry-credentials-image-secret'; - const address = 'https://index.openshift.io/v'; - const addressUpdated = 'https://index.openshift.io/updated/v1'; - const username = 'username'; - const password = 'password'; - const username0 = 'username0'; - const password0 = 'password0'; - const username1 = 'username1'; - const password1 = 'password1'; - const usernameUpdated = 'usernameUpdated'; - const passwordUpdated = 'passwordUpdated'; - const mail = 'test@secret.com'; - const mailUpdated = 'testUpdated@secret.com'; - - const credentialsToCheck = { - '.dockerconfigjson': { - auths: { - 'https://index.openshift.io/v0': { - username: username0, - password: password0, - auth: secretsView.encode(username0, password0), - email: 'test@secret.com0', - }, - 'https://index.openshift.io/v1': { - username: username1, - password: password1, - auth: secretsView.encode(username1, password1), - email: 'test@secret.com1', - }, - }, - }, - }; - const updatedCredentialsToCheck = { - '.dockerconfigjson': { - auths: { - 'https://index.openshift.io/updated/v1': { - username: usernameUpdated, - password: passwordUpdated, - auth: secretsView.encode(usernameUpdated, passwordUpdated), - email: 'testUpdated@secret.com', - }, - }, - }, - }; - - beforeAll(async () => secretsView.visitSecretsPage(appHost, testName)); - - it('creates registry credentials image secret', async () => { - await secretsView.createSecret( - secretsView.createImageSecretLink, - testName, - credentialsImageSecretName, - async () => { - await browser.wait( - until.and( - crudView.untilNoLoadersPresent, - until.presenceOf(secretsView.addSecretEntryLink), - ), - ); - await secretsView.addSecretEntryLink.click(); - await secretsView.imageSecretForm.each(async (el, index) => { - await el.$('input[name=address]').sendKeys(address + index); - await el.$('input[name=username]').sendKeys(username + index); - await el.$('input[name=password]').sendKeys(password + index); - await el.$('input[name=email]').sendKeys(mail + index); - }); - }, - ); - }); - - it('check for created registry credentials image secret values', async () => { - await secretsView.checkSecret(testName, credentialsImageSecretName, credentialsToCheck, true); - }); - - it('edits registry credentials image secret', async () => { - await secretsView.editSecret(testName, credentialsImageSecretName, async () => { - await secretsView.removeSecretEntryLink.click(); - await secretsView.secretAddressInput.clear(); - await secretsView.secretAddressInput.sendKeys(addressUpdated); - await secretsView.secretUsernameInput.clear(); - await secretsView.secretUsernameInput.sendKeys(usernameUpdated); - await secretsView.secretPasswordInput.clear(); - await secretsView.secretPasswordInput.sendKeys(passwordUpdated); - await secretsView.secretEmailInput.clear(); - await secretsView.secretEmailInput.sendKeys(mailUpdated); - }); - }); - - it('check for edited registry credentials image secret value', async () => { - await secretsView.checkSecret( - testName, - credentialsImageSecretName, - updatedCredentialsToCheck, - true, - ); - }); - - it('deletes the registry credentials image secret', async () => { - await crudView.deleteResource('secrets', 'Secret', credentialsImageSecretName); - }); - }); - - describe('Upload configuration file image secret', () => { - const uploadConfigFileImageSecretName = 'upload-configuration-file-image-secret'; - const username = 'username'; - const password = 'password'; - const configFile = { - auths: { - 'https://index.openshift.io/v1': { - username, - password, - auth: secretsView.encode(username, password), - email: 'test@secret.com', - }, - }, - }; - - beforeAll(async () => secretsView.visitSecretsPage(appHost, testName)); - - it('creates image secret by uploading configuration file', async () => { - await secretsView.createSecret( - secretsView.createImageSecretLink, - testName, - uploadConfigFileImageSecretName, - async () => { - await secretsView.authTypeDropdown.click(); - await secretsView.authConfigFileOption.click(); - await browser.wait(until.presenceOf(secretsView.uploadFileTextArea)); - await secretsView.uploadFileTextArea.sendKeys(JSON.stringify(configFile)); - }, - ); - }); - - it('check for created image secret values from uploaded configuration file', async () => { - await secretsView.checkSecret( - testName, - uploadConfigFileImageSecretName, - { '.dockerconfigjson': configFile }, - true, - ); - }); - - it('deletes the image secret created from uploaded configuration file', async () => { - await crudView.deleteResource('secrets', 'Secret', uploadConfigFileImageSecretName); - }); - }); - - describe('Key/Value secrets', () => { - const keyValueSecretName = 'key-value-secret'; - const key = 'key'; - const value = 'value'; - const key0 = 'key0'; - const value0 = 'value0'; - const key1 = 'key1'; - const value1 = 'value1'; - const keyUpdated = 'keyUpdated'; - const valueUpdated = 'valueUpdated'; - - beforeAll(async () => secretsView.visitSecretsPage(appHost, testName)); - - it('creates Key/Value secret', async () => { - await secretsView.createSecret( - secretsView.createGenericSecretLink, - testName, - keyValueSecretName, - async () => { - await browser.wait( - until.and( - crudView.untilNoLoadersPresent, - until.presenceOf(secretsView.addSecretEntryLink), - ), - ); - await secretsView.addSecretEntryLink.click(); - await browser.wait(waitForCount($$('.co-file-dropzone__textarea'), 2)); - await secretsView.genericSecretForm.each(async (el, index) => { - await el.$('input[name=key]').sendKeys(key + index); - await el.$('.co-file-dropzone__textarea').sendKeys(value + index); - }); - }, - ); - }); - - it('check for created Key/Value secret values', async () => { - await secretsView.checkSecret(testName, keyValueSecretName, { - [key0]: value0, - [key1]: value1, - }); - }); - - it('edits Key/Value secret', async () => { - await secretsView.editSecret(testName, keyValueSecretName, async () => { - await secretsView.removeSecretEntryLink.click(); - await secretsView.secretKeyInput.clear(); - await secretsView.secretKeyInput.sendKeys(keyUpdated); - await secretsView.uploadFileTextArea.clear(); - await secretsView.uploadFileTextArea.sendKeys(valueUpdated); - }); - }); - - it('check for edited Key/Value secret values', async () => { - await secretsView.checkSecret(testName, keyValueSecretName, { [keyUpdated]: valueUpdated }); - }); - - it('deletes the Key/Value secret', async () => { - await crudView.deleteResource('secrets', 'Secret', keyValueSecretName); - }); - }); -}); - -describe('Add Secret to Workloads', () => { - const secretName = 'test-secret'; - const resourceName = 'test-deploy'; - const resourceKind = 'deployment'; - const envPrefix = 'env-'; - const mountPath = '/tmp/testdata'; - const deployment: DeploymentKind = { - apiVersion: 'apps/v1', - kind: 'Deployment', - metadata: { - name: resourceName, - namespace: testName, - }, - spec: { - selector: { - matchLabels: { - test: 'add-secret-to-workload', - }, - }, - template: { - metadata: { - labels: { - test: 'add-secret-to-workload', - }, - }, - spec: { - containers: [ - { - name: 'httpd', - image: 'image-registry.openshift-image-registry.svc:5000/openshift/httpd:latest', - }, - ], - }, - }, - }, - }; - - beforeAll(() => { - // create deployment and secret - execSync(`echo '${JSON.stringify(deployment)}' | kubectl create -n ${testName} -f -`); - execSync( - `kubectl create secret generic ${secretName} --from-literal=key1=supersecret -n ${testName}`, - ); - }); - - beforeEach(async () => secretsView.visitSecretDetailsPage(appHost, testName, secretName)); - - afterEach(() => { - checkLogs(); - checkErrors(); - }); - - describe('Add Secret to Workloads as Enviroment Variables', () => { - it('Add Secret to Deployment as Env', async () => { - await secretsView.addSecretToWorkloadAsEnv(resourceName, envPrefix); - await new Promise((resolve) => - (function checkForValues() { - const output = secretsView.getResourceJSON(resourceName, testName, resourceKind); - if (JSON.parse(output).status.observedGeneration === 2) { - return resolve(); - } - setTimeout(checkForValues, 2000); - })(), - ); - expect( - secretsView.isValueInJSONPath( - 'spec.template.spec.containers[0].envFrom[0].secretRef.name', - secretName, - resourceName, - testName, - resourceKind, - ), - ).toBe(true); - expect( - secretsView.isValueInJSONPath( - 'spec.template.spec.containers[0].envFrom[0].prefix', - envPrefix, - resourceName, - testName, - resourceKind, - ), - ).toBe(true); - }); - }); - - describe('Add Secret to Workloads as Volume', () => { - it('Add Secret to Deployment as Vol', async () => { - await secretsView.addSecretToWorkloadAsVol(resourceName, mountPath); - await new Promise((resolve) => - (function checkForValues() { - const output = secretsView.getResourceJSON(resourceName, testName, resourceKind); - if (JSON.parse(output).status.observedGeneration === 3) { - return resolve(); - } - setTimeout(checkForValues, 2000); - })(), - ); - expect( - secretsView.isValueInJSONPath( - 'spec.template.spec.containers[0].volumeMounts[0].name', - secretName, - resourceName, - testName, - resourceKind, - ), - ).toBe(true); - expect( - secretsView.isValueInJSONPath( - 'spec.template.spec.containers[0].volumeMounts[0].mountPath', - mountPath, - resourceName, - testName, - resourceKind, - ), - ).toBe(true); - }); - }); -}); 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/monitoring.view.ts b/frontend/integration-tests/views/monitoring.view.ts deleted file mode 100644 index bd066578a189..000000000000 --- a/frontend/integration-tests/views/monitoring.view.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { Base64 } from 'js-base64'; - -import { $, $$, browser, by, element, ExpectedConditions as until } from 'protractor'; -import * as crudView from '../views/crud.view'; -import { firstElementByTestID } from '../protractor.conf'; - -export const wait = async (condition) => await browser.wait(condition, 20000); - -export const labels = $$('.co-label'); -export const saveButton = $('button[type=submit]'); - -// YAML form -export const successAlert = $('.pf-m-success'); - -// Configuration Overview -export const alertRoutingHeader = $('[data-test-section-heading="Alert routing"]'); -export const alertRoutingEditButton = $('.co-alert-manager-config__edit-alert-routing-btn'); -export const disabledDeleteReceiverMenuItem = $( - '.pf-c-dropdown__menu-item.pf-m-disabled[data-test-action="Delete Receiver"]', -); - -const firstRow = element.all(by.css(`[data-test-rows="resource-row"]`)).first(); - -export const openFirstRowKebabMenu = () => { - return firstRow - .$('[data-test-id="kebab-button"]') - .click() - .then(() => browser.wait(until.visibilityOf($('[data-test-id="action-items"]')))); -}; - -export const clickFirstRowKebabAction = (actionLabel: string) => { - return firstRow - .$('[data-test-id="kebab-button"]') - .click() - .then(() => browser.wait(until.elementToBeClickable(crudView.actionForLabel(actionLabel)))) - .then(() => crudView.actionForLabel(actionLabel).click()); -}; - -export const getFirstRowAsText = () => { - return firstRow.getText().then((text) => { - return text.replace(/[\n\r]/g, ' '); - }); -}; - -export const saveAsDefault = firstElementByTestID('save-as-default'); -export const sendResolvedAlerts = firstElementByTestID('send-resolved-alerts'); -export const showAdvancedConfiguration = $('button.pf-c-expandable-section__toggle'); -export const defaultAlertmanagerYaml = Base64.encode(`"global": - "resolve_timeout": "5m" -"inhibit_rules": -- "equal": - - "namespace" - - "alertname" - "source_match": - "severity": "critical" - "target_match_re": - "severity": "warning|info" -- "equal": - - "namespace" - - "alertname" - "source_match": - "severity": "warning" - "target_match_re": - "severity": "info" -"receivers": -- "name": "Default" -- "name": "Watchdog" -- "name": "Critical" -"route": - "group_by": - - "namespace" - "group_interval": "5m" - "group_wait": "30s" - "receiver": "Default" - "repeat_interval": "12h" - "routes": - - "match": - "alertname": "Watchdog" - "receiver": "Watchdog" - - "match": - "severity": "critical" - "receiver": "Critical"`); 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/alertmanager/alertmanager.cy.ts b/frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/alertmanager.cy.ts new file mode 100644 index 000000000000..a8a48c33b173 --- /dev/null +++ b/frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/alertmanager.cy.ts @@ -0,0 +1,109 @@ +// import * as _ from 'lodash'; +import { checkErrors, testName } from '../../../support'; +import { alertmanager } from '../../../views/alertmanager'; +import { detailsPage } from '../../../views/details-page'; +import { listPage } from '../../../views/list-page'; +import { modal } from '../../../views/modal'; +import { nav } from '../../../views/nav'; +import * as yamlEditor from '../../../views/yaml-editor'; + +describe('Alertmanager', () => { + before(() => { + cy.login(); + cy.initAdmin(); + }); + + afterEach(() => { + checkErrors(); + }); + + after(() => { + alertmanager.reset(); + }); + + it('displays the Alertmanager Configuration Details page', () => { + nav.sidenav.clickNavLink(['Administration', 'Cluster Settings']); + detailsPage.selectTab('Configuration'); + cy.byLegacyTestID('Alertmanager').click(); + cy.byTestSectionHeading('Alert routing').should('exist'); + }); + + it('launches Alert Routing modal, edits and saves correctly', () => { + alertmanager.visitAlertmanagerPage(); + cy.byTestID('edit-alert-routing-btn').click(); + cy.byLegacyTestID('input-group-by').type(', cluster'); + cy.byLegacyTestID('input-group-wait').clear(); + cy.byLegacyTestID('input-group-wait').type('60s'); + cy.byLegacyTestID('input-group-interval').clear(); + cy.byLegacyTestID('input-group-interval').type('10m'); + cy.byLegacyTestID('input-repeat-interval').clear(); + cy.byLegacyTestID('input-repeat-interval').type('24h'); + cy.byTestID('confirm-action').click(); + modal.shouldBeClosed(); + cy.byLegacyTestID('group_by_value').should('contain', ', cluster'); + cy.byLegacyTestID('group_wait_value').should('contain', '60s'); + cy.byLegacyTestID('group_interval_value').should('contain', '10m'); + cy.byLegacyTestID('repeat_interval_value').should('contain', '24h'); + }); + + it('displays the Alertmanager YAML page and saves Alertmanager YAML', () => { + alertmanager.visitAlertmanagerPage(); + detailsPage.selectTab('yaml'); + yamlEditor.isLoaded(); + cy.get('.yaml-editor__buttons .pf-m-success').should('not.exist'); + yamlEditor.clickSaveCreateButton(); + cy.get('.yaml-editor__buttons .pf-m-success').should('exist'); + }); + + it('creates and deletes a receiver', () => { + cy.log('create Webhook Receiver'); + const receiverName = `WebhookReceiver-${testName}`; + const receiverType = 'webhook'; + const configName = `${receiverType}_configs`; + const severity = 'severity'; + const warning = 'warning'; + const webhookURL = 'http://mywebhookurl'; + alertmanager.createReceiver(receiverName, configName); + alertmanager.showAdvancedConfiguration(); + cy.byLegacyTestID('send-resolved-alerts').should('be.checked'); + cy.byLegacyTestID('webhook-url').type(webhookURL); + cy.byLegacyTestID('label-name-0').type(severity); + cy.byLegacyTestID('label-value-0').type(warning); + alertmanager.save(); + alertmanager.validateCreation(receiverName, receiverType, severity, warning); + listPage.rows.clickKebabAction(receiverName, 'Delete Receiver'); + modal.submit(); + modal.shouldBeClosed(); + listPage.rows.shouldNotExist(receiverName); + }); + + it('prevents deletion and form edit of a receiver with sub-route', () => { + const yaml = `route: + routes: + - match: + service: database + receiver: team-DB-pager + routes: + - match: + owner: team-X + receiver: team-X-pager +receivers: +- name: 'team-X-pager' +- name: 'team-DB-pager'`; + alertmanager.visitAlertmanagerPage(); + detailsPage.selectTab('yaml'); + yamlEditor.isLoaded(); + yamlEditor.setEditorContent(yaml); + yamlEditor.clickSaveCreateButton(); + cy.get('.yaml-editor__buttons .pf-m-success').should('exist'); + detailsPage.selectTab('details'); + cy.get(`[data-test-rows="resource-row"]`) + .contains('team-X-pager') + .parents('tr') + .within(() => { + cy.get('[data-test-id="kebab-button"]').click(); + }); + cy.get('[data-test-action="Delete Receiver"]').should('be.disabled'); + alertmanager.reset(); + }); +}); diff --git a/frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/receivers/email.cy.ts b/frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/receivers/email.cy.ts new file mode 100644 index 000000000000..d63ca5811dcc --- /dev/null +++ b/frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/receivers/email.cy.ts @@ -0,0 +1,122 @@ +import * as _ from 'lodash'; +import { checkErrors, testName } from '../../../../support'; +import { alertmanager, getGlobalsAndReceiverConfig } from '../../../../views/alertmanager'; +import * as yamlEditor from '../../../../views/yaml-editor'; + +const receiverName = `EmailReceiver-${testName}`; +const receiverType = 'email'; +const configName = `${receiverType}_configs`; +const localhost = 'localhost'; +const severity = 'severity'; +const warning = 'warning'; +const emailTo = 'you@there.com'; +const emailFrom = 'me@here.com'; +const emailSmarthost = 'smarthost:8080'; +const username = 'username'; +const password = 'password'; +const identity = 'identity'; +const secret = 'secret'; +const html = 'myhtml'; + +describe('Alertmanager: Email Receiver Form', () => { + before(() => { + cy.login(); + cy.initAdmin(); + }); + + afterEach(() => { + checkErrors(); + }); + + after(() => { + alertmanager.reset(); + }); + + it('creates and edits Email Receiver correctly', () => { + cy.log('create Email Receiver'); + alertmanager.createReceiver(receiverName, configName); + // prior to smtp change, save as default is disabled + cy.byLegacyTestID('save-as-default').should('be.disabled'); + cy.byLegacyTestID('email-hello').invoke('val').should('eq', localhost); + cy.byLegacyTestID('email-require-tls').should('be.checked'); + alertmanager.showAdvancedConfiguration(); + cy.byLegacyTestID('send-resolved-alerts').should('not.be.checked'); + cy.byLegacyTestID('email-html') + .invoke('val') + .should('eq', '{{ template "email.default.html" . }}'); + cy.byLegacyTestID('email-to').type(emailTo); + cy.byLegacyTestID('email-from').type(emailFrom); + cy.byLegacyTestID('save-as-default').should('be.enabled'); + cy.byLegacyTestID('email-smarthost').type(emailSmarthost); + cy.byLegacyTestID('label-name-0').type(severity); + cy.byLegacyTestID('label-value-0').type(warning); + alertmanager.save(); + + cy.log('verify Email Receiver was created correctly'); + alertmanager.validateCreation(receiverName, receiverType, severity, warning); + alertmanager.visitYAMLPage(); + yamlEditor.getEditorContent().then((content) => { + const configs = getGlobalsAndReceiverConfig(receiverName, configName, content); + expect(_.has(configs.globals, 'email_to')).toBeFalsy(); + expect(_.has(configs.globals, 'smtp_from')).toBeFalsy(); + expect(_.has(configs.globals, 'smtp_smarthost')).toBeFalsy(); + expect(_.has(configs.globals, 'smtp_require_tls')).toBeFalsy(); + expect(configs.receiverConfig.to).toBe(emailTo); + expect(configs.receiverConfig.from).toBe(emailFrom); + expect(configs.receiverConfig.smarthost).toBe(emailSmarthost); + expect(_.has(configs.receiverConfig, 'require_tls')).toBeFalsy(); // unchanged from global value + }); + + cy.log('save globals and advanced fields correctly'); + alertmanager.visitEditPage(receiverName); + cy.byLegacyTestID('email-to').invoke('val').should('eq', emailTo); + cy.byLegacyTestID('save-as-default').should('be.enabled'); // smtp_from different from global + cy.byLegacyTestID('save-as-default').should('not.be.checked'); + cy.byLegacyTestID('email-from').invoke('val').should('eq', emailFrom); + cy.byLegacyTestID('email-hello').invoke('val').should('eq', localhost); + cy.byLegacyTestID('email-auth-username').type(username); + cy.byLegacyTestID('email-auth-password').type(password); + cy.byLegacyTestID('email-auth-identity').type(identity); + cy.byLegacyTestID('email-auth-secret').type(secret); + cy.byLegacyTestID('email-require-tls').click(); + alertmanager.showAdvancedConfiguration(); + cy.byLegacyTestID('send-resolved-alerts').click(); + cy.byLegacyTestID('email-html').clear(); + cy.byLegacyTestID('email-html').type(html); + alertmanager.save(); + + cy.log('verify globals and advanced fields were saved correctly'); + alertmanager.visitYAMLPage(); + yamlEditor.getEditorContent().then((content) => { + const configs = getGlobalsAndReceiverConfig(receiverName, configName, content); + expect(_.has(configs.globals, 'smtp_auth_username')).toBeFalsy(); + expect(configs.receiverConfig.auth_username).toBe(username); + expect(configs.receiverConfig.auth_password).toBe(password); + expect(configs.receiverConfig.auth_identity).toBe(identity); + expect(configs.receiverConfig.auth_secret).toBe(secret); + expect(configs.receiverConfig.require_tls).toBeFalsy(); + expect(configs.receiverConfig.send_resolved).toBeTruthy(); + expect(configs.receiverConfig.html).toBe(html); + }); + + cy.log('save as default'); + alertmanager.visitEditPage(receiverName); + cy.byLegacyTestID('save-as-default').should('not.be.checked'); + cy.byLegacyTestID('save-as-default').click(); + alertmanager.save(); + alertmanager.visitYAMLPage(); + yamlEditor.getEditorContent().then((content) => { + const configs = getGlobalsAndReceiverConfig(receiverName, configName, content); + expect(configs.globals.smtp_from).toBe(emailFrom); + expect(configs.globals.smtp_hello).toBe(localhost); + expect(configs.globals.smtp_smarthost).toBe(emailSmarthost); + expect(configs.globals.smtp_auth_username).toBe(username); + expect(configs.globals.smtp_auth_password).toBe(password); + expect(configs.globals.smtp_auth_identity).toBe(identity); + expect(configs.globals.smtp_auth_secret).toBe(secret); + expect(configs.globals.smtp_require_tls).toBeFalsy(); + // non-global fields should still be saved with Receiver + expect(configs.receiverConfig.to).toBe(emailTo); + }); + }); +}); diff --git a/frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/receivers/pagerduty.cy.ts b/frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/receivers/pagerduty.cy.ts new file mode 100644 index 000000000000..428389f8f5ab --- /dev/null +++ b/frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/receivers/pagerduty.cy.ts @@ -0,0 +1,161 @@ +import * as _ from 'lodash'; +import { checkErrors, testName } from '../../../../support'; +import { alertmanager, getGlobalsAndReceiverConfig } from '../../../../views/alertmanager'; +import { listPage } from '../../../../views/list-page'; +import * as yamlEditor from '../../../../views/yaml-editor'; + +const receiverName = `PagerDutyReceiver-${testName}`; +const receiverType = 'pagerduty'; +const configName = `${receiverType}_configs`; +const severity = 'severity'; +const warning = 'warning'; +const pagerDutyClient = '{{ template "pagerduty.default.client" . }}'; +const pagerDutyClientURL = '{{ template "pagerduty.default.clientURL" . }}'; +const pagerDutyURL1 = 'http://pagerduty-url-specific-to-receiver'; +const pagerDutyURL2 = 'http://global-pagerduty-url'; +const pagerDutyURL3 = 'http://pagerduty-url-specific-to-receiver'; +const clientURL = 'http://updated-client-url'; +const pagerDutyDescription = 'new description'; + +describe('Alertmanager: PagerDuty Receiver Form', () => { + before(() => { + cy.login(); + cy.initAdmin(); + }); + + afterEach(() => { + checkErrors(); + }); + + after(() => { + alertmanager.reset(); + }); + + it('creates and edits PagerDuty Receiver correctly', () => { + cy.log('create PagerDuty Receiver'); + alertmanager.createReceiver(receiverName, configName); + cy.byLegacyTestID('integration-key').type(''); + cy.byLegacyTestID('pagerduty-url') + .invoke('val') + .should('eq', 'https://events.pagerduty.com/v2/enqueue'); + alertmanager.showAdvancedConfiguration(); + cy.byLegacyTestID('send-resolved-alerts').should('be.checked'); + cy.byLegacyTestID('pagerduty-client').invoke('val').should('eq', pagerDutyClient); + cy.byLegacyTestID('pagerduty-client-url').invoke('val').should('eq', pagerDutyClientURL); + cy.byLegacyTestID('pagerduty-description') + .invoke('val') + .should('eq', '{{ template "pagerduty.default.description" .}}'); + cy.byLegacyTestID('pagerduty-severity').invoke('val').should('eq', 'error'); + cy.byLegacyTestID('label-name-0').type(severity); + cy.byLegacyTestID('label-value-0').type(warning); + alertmanager.save(); + + cy.log('verify PagerDuty Receiver was created correctly'); + alertmanager.validateCreation(receiverName, receiverType, severity, warning); + + cy.log('update pagerduty_url'); + listPage.rows.clickKebabAction(receiverName, 'Edit Receiver'); + // Save as default checkbox disabled when url equals global url + cy.byLegacyTestID('save-as-default').should('be.disabled'); + // changing url enables Save as default checkbox, should save pagerduty_url with Receiver + cy.byLegacyTestID('pagerduty-url').clear(); + cy.byLegacyTestID('pagerduty-url').type(pagerDutyURL1); + cy.byLegacyTestID('save-as-default').should('be.enabled'); + alertmanager.save(); + + cy.log('verify pagerduty_url was saved with Receiver and not global'); + alertmanager.visitYAMLPage(); + yamlEditor.getEditorContent().then((content) => { + const configs = getGlobalsAndReceiverConfig(receiverName, configName, content); + expect(_.has(configs.globals, 'pagerduty_url')).toBeFalsy(); + expect(configs.receiverConfig.url).toBe(pagerDutyURL1); + }); + + cy.log('save pagerduty_url as global'); + alertmanager.visitEditPage(receiverName); + cy.byLegacyTestID('pagerduty-url').clear(); + cy.byLegacyTestID('pagerduty-url').type(pagerDutyURL2); + cy.byLegacyTestID('save-as-default').should('be.enabled').check(); + alertmanager.save(); + + cy.log('verify pagerduty_url was saved as global'); + alertmanager.visitYAMLPage(); + yamlEditor.getEditorContent().then((content) => { + const configs = getGlobalsAndReceiverConfig(receiverName, configName, content); + expect(configs.globals.pagerduty_url).toBe(pagerDutyURL2); + expect(_.has(configs.receiverConfig, 'url')).toBeFalsy(); + }); + + cy.log('add pagerduty_url to receiver with existing global'); + alertmanager.visitEditPage(receiverName); + cy.byLegacyTestID('pagerduty-url').clear(); + cy.byLegacyTestID('pagerduty-url').type(pagerDutyURL3); + cy.byLegacyTestID('save-as-default').should('be.enabled'); + cy.byLegacyTestID('save-as-default').should('not.be.checked'); + alertmanager.save(); + + cy.log( + 'verify pagerduty_url should be saved with Receiver, as well as having a global pagerduty_url prop', + ); + alertmanager.visitYAMLPage(); + yamlEditor.getEditorContent().then((content) => { + const configs = getGlobalsAndReceiverConfig(receiverName, configName, content); + expect(configs.globals.pagerduty_url).toBe(pagerDutyURL2); + expect(configs.receiverConfig.url).toBe(pagerDutyURL3); + }); + + cy.log('update advanced configuration fields correctly'); + alertmanager.visitEditPage(receiverName); + alertmanager.showAdvancedConfiguration(); + cy.byLegacyTestID('send-resolved-alerts').should('be.checked').click(); + cy.byLegacyTestID('send-resolved-alerts').should('not.be.checked'); + cy.byLegacyTestID('pagerduty-client').clear(); + cy.byLegacyTestID('pagerduty-client').type('updated-client'); + cy.byLegacyTestID('pagerduty-client-url').clear(); + cy.byLegacyTestID('pagerduty-client-url').type(clientURL); + alertmanager.save(); + + cy.log('verify 3 changed fields should be saved with Receiver'); + alertmanager.visitYAMLPage(); + yamlEditor.getEditorContent().then((content) => { + const configs = getGlobalsAndReceiverConfig(receiverName, configName, content); + expect(configs.receiverConfig.send_resolved).toBeFalsy(); + expect(configs.receiverConfig.client).toBe('updated-client'); + expect(configs.receiverConfig.client_url).toBe('http://updated-client-url'); + expect(configs.receiverConfig.description).toBe(undefined); + expect(configs.receiverConfig.severity).toBe(undefined); + }); + + cy.log( + 'restore default values for the 3, change desc and severity - which should then be saved with Receiver while initial 3 are removed from Receiver config', + ); + alertmanager.visitEditPage(receiverName); + alertmanager.showAdvancedConfiguration(); + cy.byLegacyTestID('send-resolved-alerts').should('not.be.checked').click(); + cy.byLegacyTestID('send-resolved-alerts').should('be.checked'); + cy.byLegacyTestID('pagerduty-client').clear(); + cy.byLegacyTestID('pagerduty-client').type(pagerDutyClient, { + parseSpecialCharSequences: false, + }); + cy.byLegacyTestID('pagerduty-client-url').clear(); + cy.byLegacyTestID('pagerduty-client-url').type(pagerDutyClientURL, { + parseSpecialCharSequences: false, + }); + cy.byLegacyTestID('pagerduty-description').clear(); + cy.byLegacyTestID('pagerduty-description').type(pagerDutyDescription); + cy.byLegacyTestID('pagerduty-severity').clear(); + cy.byLegacyTestID('pagerduty-severity').type(severity); + alertmanager.save(); + + cy.log('verify'); + alertmanager.visitYAMLPage(); + yamlEditor.getEditorContent().then((content) => { + const configs = getGlobalsAndReceiverConfig(receiverName, configName, content); + expect(configs.receiverConfig.send_resolved).toBe(undefined); + expect(configs.receiverConfig.client).toBe(undefined); + expect(configs.receiverConfig.client_url).toBe(undefined); + expect(configs.receiverConfig.description).toBe(pagerDutyDescription); + expect(configs.receiverConfig.severity).toBe(severity); + }); + }); +}); diff --git a/frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/receivers/slack.cy.ts b/frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/receivers/slack.cy.ts new file mode 100644 index 000000000000..ff56258fef41 --- /dev/null +++ b/frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/receivers/slack.cy.ts @@ -0,0 +1,105 @@ +import * as _ from 'lodash'; +import { checkErrors, testName } from '../../../../support'; +import { alertmanager, getGlobalsAndReceiverConfig } from '../../../../views/alertmanager'; +import * as yamlEditor from '../../../../views/yaml-editor'; + +const receiverName = `SlackReceiver-${testName}`; +const receiverType = 'slack'; +const configName = `${receiverType}_configs`; +const severity = 'severity'; +const warning = 'warning'; +const slackAPIURL = 'http://myslackapi'; +const slackChannel = 'myslackchannel'; +const slackIconURL = 'http://slackiconurl'; +const slackUsername = 'slackusername'; + +describe('Alertmanager: Slack Receiver Form', () => { + before(() => { + cy.login(); + cy.initAdmin(); + }); + + afterEach(() => { + checkErrors(); + }); + + after(() => { + alertmanager.reset(); + }); + + it('creates and edits Slack Receiver correctly', () => { + cy.log('create Slack Receiver'); + alertmanager.createReceiver(receiverName, configName); + cy.byLegacyTestID('save-as-default').should('be.disabled'); + alertmanager.showAdvancedConfiguration(); + cy.byLegacyTestID('send-resolved-alerts').should('not.be.checked'); + cy.byLegacyTestID('slack-icon-url') + .invoke('val') + .should('eq', '{{ template "slack.default.iconurl" .}}'); + cy.byLegacyTestID('slack-icon-emoji').should('not.exist'); + cy.byLegacyTestID('slack-icon-type-emoji').click(); + cy.byLegacyTestID('slack-icon-url').should('not.exist'); + cy.byLegacyTestID('slack-icon-emoji') + .invoke('val') + .should('eq', '{{ template "slack.default.iconemoji" .}}'); + cy.byLegacyTestID('slack-username') + .invoke('val') + .should('eq', '{{ template "slack.default.username" . }}'); + cy.byLegacyTestID('slack-link-names').should('not.be.checked'); + cy.byLegacyTestID('slack-api-url').type(slackAPIURL); + cy.byLegacyTestID('save-as-default').should('be.enabled'); + cy.byLegacyTestID('slack-channel').type(slackChannel); + cy.byLegacyTestID('label-name-0').type(severity); + cy.byLegacyTestID('label-value-0').type(warning); + alertmanager.save(); + + cy.log('verify Slack Receiver was created correctly'); + alertmanager.validateCreation(receiverName, receiverType, severity, warning); + alertmanager.visitYAMLPage(); + yamlEditor.getEditorContent().then((content) => { + const configs = getGlobalsAndReceiverConfig(receiverName, configName, content); + expect(_.has(configs.globals, 'slack_api_url')).toBeFalsy(); + expect(configs.receiverConfig.channel).toBe(slackChannel); + expect(configs.receiverConfig.api_url).toBe(slackAPIURL); + // make sure adv fields are not saved since they equal their global values + expect(_.has(configs.receiverConfig, 'send_resolved')).toBeFalsy(); + expect(_.has(configs.receiverConfig, 'username')).toBeFalsy(); + }); + + cy.log('save globals and advanced fields correctly'); + alertmanager.visitEditPage(receiverName); + cy.byLegacyTestID('slack-channel').invoke('val').should('eq', slackChannel); + cy.byLegacyTestID('save-as-default').should('be.enabled'); + cy.byLegacyTestID('slack-api-url').invoke('val').should('eq', slackAPIURL); + alertmanager.showAdvancedConfiguration(); + cy.byLegacyTestID('send-resolved-alerts').click(); + cy.byLegacyTestID('slack-icon-url').clear(); + cy.byLegacyTestID('slack-icon-url').type(slackIconURL); + cy.byLegacyTestID('slack-username').clear(); + cy.byLegacyTestID('slack-username').type(slackUsername); + cy.byLegacyTestID('slack-link-names').click(); + cy.byLegacyTestID('save-as-default').click(); + alertmanager.save(); + + cy.log('verify advanced fields were saved correctly'); + alertmanager.visitEditPage(receiverName); + alertmanager.showAdvancedConfiguration(); + cy.byLegacyTestID('send-resolved-alerts').should('be.checked'); + cy.byLegacyTestID('slack-icon-url').invoke('val').should('eq', slackIconURL); + cy.byLegacyTestID('slack-icon-emoji').should('not.exist'); + cy.byLegacyTestID('slack-username').invoke('val').should('eq', slackUsername); + cy.byLegacyTestID('slack-link-names').should('be.checked'); + alertmanager.visitAlertmanagerPage(); + alertmanager.visitYAMLPage(); + yamlEditor.getEditorContent().then((content) => { + const configs = getGlobalsAndReceiverConfig(receiverName, configName, content); + expect(configs.globals.slack_api_url).toBe(slackAPIURL); + expect(_.has(configs.receiverConfig, 'api_url')).toBeFalsy(); + expect(configs.receiverConfig.channel).toBe('myslackchannel'); + expect(configs.receiverConfig.send_resolved).toBeTruthy(); + expect(configs.receiverConfig.icon_url).toBe(slackIconURL); + expect(configs.receiverConfig.username).toBe(slackUsername); + expect(configs.receiverConfig.link_names).toBeTruthy(); + }); + }); +}); diff --git a/frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/receivers/webhook.cy.ts b/frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/receivers/webhook.cy.ts new file mode 100644 index 000000000000..91c6d5498f18 --- /dev/null +++ b/frontend/packages/integration-tests-cypress/tests/cluster-settings/alertmanager/receivers/webhook.cy.ts @@ -0,0 +1,67 @@ +import * as _ from 'lodash'; +import { checkErrors, testName } from '../../../../support'; +import { alertmanager, getGlobalsAndReceiverConfig } from '../../../../views/alertmanager'; +import * as yamlEditor from '../../../../views/yaml-editor'; + +const receiverName = `WebhookReceiver-${testName}`; +const receiverType = 'webhook'; +const configName = `${receiverType}_configs`; +const severity = 'severity'; +const warning = 'warning'; +const webhookURL = 'http://mywebhookurl'; +const updatedWebhookURL = 'http://myupdatedwebhookurl'; + +describe('Alertmanager: Webhook Receiver Form', () => { + before(() => { + cy.login(); + cy.initAdmin(); + }); + + afterEach(() => { + checkErrors(); + }); + + after(() => { + alertmanager.reset(); + }); + + it('creates and edits Webhook Receiver correctly', () => { + cy.log('create Webhook Receiver'); + alertmanager.createReceiver(receiverName, configName); + alertmanager.showAdvancedConfiguration(); + cy.byLegacyTestID('send-resolved-alerts').should('be.checked'); + cy.byLegacyTestID('webhook-url').type(webhookURL); + cy.byLegacyTestID('label-name-0').type(severity); + cy.byLegacyTestID('label-value-0').type(warning); + alertmanager.save(); + + cy.log('verify Webhook Receiver was created correctly'); + alertmanager.validateCreation(receiverName, receiverType, severity, warning); + alertmanager.visitYAMLPage(); + yamlEditor.getEditorContent().then((content) => { + const configs = getGlobalsAndReceiverConfig(receiverName, configName, content); + expect(configs.receiverConfig.url).toBe(webhookURL); + expect(_.has(configs.receiverConfig, 'send_resolved')).toBeFalsy(); + }); + + cy.log('edits Webhook Receiver and saves advanced fields correctly'); + alertmanager.visitEditPage(receiverName); + cy.byLegacyTestID('webhook-url').invoke('val').should('eq', webhookURL); + cy.byLegacyTestID('webhook-url').clear(); + cy.byLegacyTestID('webhook-url').type(updatedWebhookURL); + alertmanager.showAdvancedConfiguration(); + cy.byLegacyTestID('send-resolved-alerts').click(); + alertmanager.save(); + + cy.log('verify advanced fields were saved correctly'); + alertmanager.visitEditPage(receiverName); + cy.byLegacyTestID('send-resolved-alerts').should('not.be.checked'); + alertmanager.visitAlertmanagerPage(); + alertmanager.visitYAMLPage(); + yamlEditor.getEditorContent().then((content) => { + const configs = getGlobalsAndReceiverConfig(receiverName, configName, content); + expect(configs.receiverConfig.url).toBe(updatedWebhookURL); + expect(configs.receiverConfig.send_resolved).toBeFalsy(); + }); + }); +}); 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..aa237a2f2933 --- /dev/null +++ b/frontend/packages/integration-tests-cypress/tests/cluster-settings/cluster-settings.cy.ts @@ -0,0 +1,68 @@ +import { checkErrors } from '../../support'; +import { detailsPage } from '../../views/details-page'; + +describe('Cluster Settings', () => { + before(() => { + cy.login(); + 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..ae6c98b82d45 --- /dev/null +++ b/frontend/packages/integration-tests-cypress/tests/cluster-settings/oauth.cy.ts @@ -0,0 +1,85 @@ +import { checkErrors, testName } from '../../support'; +import { oauth } from '../../views/oauth'; + +describe('OAuth', () => { + let originalOAuthConfig: any; + + before(() => { + cy.login(); + 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..ddf359d4c616 --- /dev/null +++ b/frontend/packages/integration-tests-cypress/tests/crud/environment.cy.ts @@ -0,0 +1,79 @@ +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.login(); + 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/tests/crud/secrets/add-to-workload.cy.ts b/frontend/packages/integration-tests-cypress/tests/crud/secrets/add-to-workload.cy.ts new file mode 100644 index 000000000000..f75217b4f9ee --- /dev/null +++ b/frontend/packages/integration-tests-cypress/tests/crud/secrets/add-to-workload.cy.ts @@ -0,0 +1,116 @@ +import * as _ from 'lodash'; +import { DeploymentKind } from '@console/internal/module/k8s'; +import { checkErrors, testName } from '../../../support'; +import { modal } from '../../../views/modal'; +import { secrets } from '../../../views/secret'; + +const secretName = 'test-secret'; +const resourceName = 'test-deploy'; +const resourceKind = 'deployment'; +const envPrefix = 'env-'; +const mountPath = '/tmp/testdata'; +const deployment: DeploymentKind = { + apiVersion: 'apps/v1', + kind: 'Deployment', + metadata: { + name: resourceName, + namespace: testName, + }, + spec: { + selector: { + matchLabels: { + test: 'add-secret-to-workload', + }, + }, + template: { + metadata: { + labels: { + test: 'add-secret-to-workload', + }, + }, + spec: { + containers: [ + { + name: 'httpd', + image: 'image-registry.openshift-image-registry.svc:5000/openshift/httpd:latest', + }, + ], + }, + }, + }, +}; + +describe('Add Secret to Workloads', () => { + before(() => { + cy.login(); + cy.createProjectWithCLI(testName); + cy.exec(`echo '${JSON.stringify(deployment)}' | kubectl create -n ${testName} -f -`); + cy.exec( + `kubectl create secret generic ${secretName} --from-literal=key1=supersecret -n ${testName}`, + ); + }); + + beforeEach(() => { + cy.visit(`/k8s/ns/${testName}/secrets/${secretName}`); + }); + + afterEach(() => { + checkErrors(); + }); + + after(() => { + cy.deleteProjectWithCLI(testName); + }); + + it(`Adds Secret to Deployment as Environment Variables`, () => { + cy.log('Add Secret'); + secrets.addSecretToWorkload(resourceName); + cy.byTestID('Environment variables-radio-input').click(); + cy.byTestID('add-secret-to-workload-prefix').type(envPrefix); + modal.submitShouldBeEnabled(); + modal.submit(); + + cy.log('Verify Secret'); + secrets.getResourceJSON(resourceName, testName, resourceKind).then((resourceJSON) => { + const resource = JSON.parse(resourceJSON.stdout); + const name = _.get( + resource, + 'spec.template.spec.containers[0].envFrom[0].secretRef.name', + undefined, + ); + expect(name).to.equal(secretName); + const prefix = _.get( + resource, + 'spec.template.spec.containers[0].envFrom[0].prefix', + undefined, + ); + expect(prefix).to.equal(envPrefix); + }); + }); + + it(`Adds Secret to Deployment as Volume`, () => { + cy.log('Add Secret'); + secrets.addSecretToWorkload(resourceName); + cy.byTestID('Volume-radio-input').click(); + cy.byTestID('add-secret-to-workload-mountpath').type(mountPath); + modal.submitShouldBeEnabled(); + modal.submit(); + + cy.log('Verify Secret'); + secrets.getResourceJSON(resourceName, testName, resourceKind).then((resourceJSON) => { + const resource = JSON.parse(resourceJSON.stdout); + const name = _.get( + resource, + 'spec.template.spec.containers[0].volumeMounts[0].name', + undefined, + ); + expect(name).to.equal(secretName); + const mp = _.get( + resource, + 'spec.template.spec.containers[0].volumeMounts[0].mountPath', + undefined, + ); + expect(mp).to.equal(mountPath); + }); + }); +}); diff --git a/frontend/packages/integration-tests-cypress/tests/crud/secrets/image-pull.cy.ts b/frontend/packages/integration-tests-cypress/tests/crud/secrets/image-pull.cy.ts new file mode 100644 index 000000000000..8ab55c1c189b --- /dev/null +++ b/frontend/packages/integration-tests-cypress/tests/crud/secrets/image-pull.cy.ts @@ -0,0 +1,148 @@ +import { checkErrors, testName } from '../../../support'; +import { detailsPage } from '../../../views/details-page'; +import { secrets } from '../../../views/secret'; + +const heading = 'Create image pull secret'; + +describe('Image pull secrets', () => { + before(() => { + cy.login(); + cy.createProjectWithCLI(testName); + }); + + beforeEach(() => { + cy.visit(`/k8s/ns/${testName}/secrets/`); + secrets.clickCreateSecretDropdownButton('image'); + }); + + afterEach(() => { + checkErrors(); + }); + + after(() => { + cy.deleteProjectWithCLI(testName); + }); + + it(`Creates, edits, and deletes an image registry credentials pull secret`, () => { + const credentialsImageSecretName = `registry-credentials-image-secret-${testName}`; + const address = 'https://index.openshift.io/v'; + const addressUpdated = 'https://index.openshift.io/updated/v1'; + const username = 'username'; + const password = 'password'; + const username0 = `${username}0`; + const password0 = `${password}0`; + const username1 = `${username}1`; + const password1 = `${password}1`; + const usernameUpdated = `${username}Updated`; + const passwordUpdated = `${password}Updated`; + const mail = 'test@secret.com'; + const mail0 = `${mail}0`; + const mail1 = `${mail}1`; + const mailUpdated = 'testUpdated@secret.com'; + + const credentialsToCheck = { + '.dockerconfigjson': { + auths: { + 'https://index.openshift.io/v0': { + username: username0, + password: password0, + auth: secrets.encode(username0, password0), + email: mail0, + }, + 'https://index.openshift.io/v1': { + username: username1, + password: password1, + auth: secrets.encode(username1, password1), + email: mail1, + }, + }, + }, + }; + const updatedCredentialsToCheck = { + '.dockerconfigjson': { + auths: { + 'https://index.openshift.io/updated/v1': { + username: usernameUpdated, + password: passwordUpdated, + auth: secrets.encode(usernameUpdated, passwordUpdated), + email: mailUpdated, + }, + }, + }, + }; + + cy.log('Create secret'); + cy.get('.co-m-pane__heading').contains(heading); + secrets.enterSecretName(credentialsImageSecretName); + secrets.clickAddCredentialsButton(); + cy.get('[data-test-id="create-image-secret-form"]').each(($el, index) => { + cy.wrap($el).find('[data-test="image-secret-address"]').type(`${address}${index}`); + cy.wrap($el).find('[data-test="image-secret-username"]').type(`${username}${index}`); + cy.wrap($el).find('[data-test="image-secret-password"]').type(`${password}${index}`); + cy.wrap($el).find('[data-test="image-secret-email"]').type(`${mail}${index}`); + }); + secrets.save(); + secrets.detailsPageIsLoaded(credentialsImageSecretName); + + cy.log('Verify secret'); + secrets.checkSecret(credentialsToCheck, true); + + cy.log('Edit secret'); + detailsPage.clickPageActionFromDropdown('Edit Secret'); + secrets.clickRemoveEntryButton(); + cy.byTestID('image-secret-address').clear(); + cy.byTestID('image-secret-address').type(addressUpdated); + cy.byTestID('image-secret-username').clear(); + cy.byTestID('image-secret-username').type(usernameUpdated); + cy.byTestID('image-secret-password').clear(); + cy.byTestID('image-secret-password').type(passwordUpdated); + cy.byTestID('image-secret-email').clear(); + cy.byTestID('image-secret-email').type(mailUpdated); + secrets.save(); + + cy.log('Verify edit'); + secrets.detailsPageIsLoaded(credentialsImageSecretName); + secrets.checkSecret(updatedCredentialsToCheck, true); + + cy.log('Delete secret'); + secrets.deleteSecret(credentialsImageSecretName); + }); + + it(`Creates and deletes an upload configuration file image pull secret`, () => { + const uploadConfigFileImageSecretName = `upload-configuration-file-image-secret-${testName}`; + const username = 'username'; + const password = 'password'; + const configFile = { + auths: { + 'https://index.openshift.io/v1': { + username, + password, + auth: secrets.encode(username, password), + email: 'test@secret.com', + }, + }, + }; + + cy.log('Create secret'); + cy.get('.co-m-pane__heading').contains(heading); + secrets.enterSecretName(uploadConfigFileImageSecretName); + cy.byLegacyTestID('dropdown-button').click(); + cy.byTestDropDownMenu('config-file').click(); + cy.byLegacyTestID('file-input-textarea').type(JSON.stringify(configFile), { + parseSpecialCharSequences: false, + }); + secrets.save(); + secrets.detailsPageIsLoaded(uploadConfigFileImageSecretName); + + cy.log('Verify secret'); + secrets.checkSecret( + { + '.dockerconfigjson': configFile, + }, + true, + ); + + cy.log('Delete secret'); + secrets.deleteSecret(uploadConfigFileImageSecretName); + }); +}); diff --git a/frontend/packages/integration-tests-cypress/tests/crud/secrets.cy.ts b/frontend/packages/integration-tests-cypress/tests/crud/secrets/key-value.cy.ts similarity index 85% rename from frontend/packages/integration-tests-cypress/tests/crud/secrets.cy.ts rename to frontend/packages/integration-tests-cypress/tests/crud/secrets/key-value.cy.ts index 1f4d48dd209d..377e1675a1e1 100644 --- a/frontend/packages/integration-tests-cypress/tests/crud/secrets.cy.ts +++ b/frontend/packages/integration-tests-cypress/tests/crud/secrets/key-value.cy.ts @@ -1,17 +1,17 @@ import 'cypress-file-upload'; -import { checkErrors, testName } from '../../support'; -import { detailsPage } from '../../views/details-page'; -import { infoMessage } from '../../views/form'; -import { listPage } from '../../views/list-page'; -import { nav } from '../../views/nav'; -import { secrets } from '../../views/secret'; +import { checkErrors, testName } from '../../../support'; +import { detailsPage } from '../../../views/details-page'; +import { infoMessage } from '../../../views/form'; +import { listPage } from '../../../views/list-page'; +import { nav } from '../../../views/nav'; +import { secrets } from '../../../views/secret'; const populateSecretForm = (name: string, key: string, fileName: string) => { cy.get('.co-m-pane__heading').contains('Create key/value secret'); cy.byTestID('secret-name').should('exist'); cy.byLegacyTestID('file-input-textarea').should('exist'); - cy.byTestID('secret-name').type(name); + secrets.enterSecretName(name); cy.byTestID('secret-key').type(key); cy.byTestID('file-input').attachFile(fileName); }; @@ -23,9 +23,9 @@ const modifySecretForm = (key: string) => { }; describe('Create key/value secrets', () => { - const binarySecretName = `${testName}binarysecretname`; - const asciiSecretName = `${testName}asciisecretname`; - const unicodeSecretName = `${testName}unicodesecretname`; + const binarySecretName = `key-value-binary-secret-${testName}`; + const asciiSecretName = `key-value-ascii-secret-${testName}`; + const unicodeSecretName = `key-value-unicode-secret-${testName}`; const binaryFilename = 'binarysecret.bin'; const asciiFilename = 'asciisecret.txt'; const unicodeFilename = 'unicodesecret.utf8'; @@ -42,7 +42,7 @@ describe('Create key/value secrets', () => { cy.visit(`/k8s/cluster/projects/${testName}`); nav.sidenav.clickNavLink(['Workloads', 'Secrets']); listPage.titleShouldHaveText('Secrets'); - secrets.clickCreateKeyValSecretDropdownButton(); + secrets.clickCreateSecretDropdownButton('generic'); }); afterEach(() => { @@ -63,7 +63,7 @@ describe('Create key/value secrets', () => { populateSecretForm(binarySecretName, secretKey, binaryFilename); cy.byLegacyTestID('file-input-textarea').should('not.exist'); cy.get(infoMessage).should('exist'); - cy.byTestID('save-changes').click(); + secrets.save(); cy.byTestID('loading-indicator').should('not.exist'); detailsPage.isLoaded(); detailsPage.titleShouldContain(binarySecretName); @@ -78,7 +78,7 @@ describe('Create key/value secrets', () => { }); }); modifySecretForm(modifiedSecretKey); - cy.byTestID('save-changes').click(); + secrets.save(); cy.byTestID('loading-indicator').should('not.exist'); detailsPage.isLoaded(); detailsPage.titleShouldContain(binarySecretName); @@ -99,7 +99,7 @@ describe('Create key/value secrets', () => { cy.fixture(asciiFilename, 'ascii').then((asciiSecret) => { cy.byLegacyTestID('file-input-textarea').should('contain.text', asciiSecret); cy.get(infoMessage).should('not.exist'); - cy.byTestID('save-changes').click(); + secrets.save(); cy.byTestID('loading-indicator').should('not.exist'); detailsPage.isLoaded(); detailsPage.titleShouldContain(asciiSecretName); @@ -119,7 +119,7 @@ describe('Create key/value secrets', () => { cy.fixture(unicodeFilename, 'utf8').then((unicodeSecret) => { cy.byLegacyTestID('file-input-textarea').should('contain.text', unicodeSecret); cy.get(infoMessage).should('not.exist'); - cy.byTestID('save-changes').click(); + secrets.save(); cy.byTestID('loading-indicator').should('not.exist'); detailsPage.isLoaded(); detailsPage.titleShouldContain(unicodeSecretName); diff --git a/frontend/packages/integration-tests-cypress/tests/crud/secrets/source.cy.ts b/frontend/packages/integration-tests-cypress/tests/crud/secrets/source.cy.ts new file mode 100644 index 000000000000..c8b8b6501c44 --- /dev/null +++ b/frontend/packages/integration-tests-cypress/tests/crud/secrets/source.cy.ts @@ -0,0 +1,97 @@ +import { checkErrors, testName } from '../../../support'; +import { detailsPage } from '../../../views/details-page'; +import { secrets } from '../../../views/secret'; + +describe('Source secrets', () => { + const basicSourceSecretName = `basic-source-secret-${testName}`; + const basicSourceSecretUsername = 'username'; + const basicSourceSecretUsernameUpdated = 'usernameUpdated'; + const basicSourceSecretPassword = 'password'; + const basicSourceSecretPasswordUpdated = 'passwordUpdated'; + const sshSourceSecretName = `ssh-source-secret-${testName}`; + const sshSourceSecretSSHKey = 'sshKey'; + const sshSourceSecretSSHKeUpdated = 'sshKeyUpdated'; + + before(() => { + cy.login(); + cy.createProjectWithCLI(testName); + }); + + beforeEach(() => { + cy.visit(`/k8s/ns/${testName}/secrets/`); + secrets.clickCreateSecretDropdownButton('source'); + }); + + afterEach(() => { + checkErrors(); + }); + + after(() => { + cy.deleteProjectWithCLI(testName); + }); + + it(`Creates, edits, and deletes a basic source secret`, () => { + cy.log('Create secret'); + cy.get('.co-m-pane__heading').contains('Create source secret'); + secrets.enterSecretName(basicSourceSecretName); + cy.byTestID('secret-username').type(basicSourceSecretUsername); + cy.byTestID('secret-password').type(basicSourceSecretPassword); + secrets.save(); + secrets.detailsPageIsLoaded(basicSourceSecretName); + + cy.log('Verify secret'); + secrets.checkSecret({ + password: basicSourceSecretPassword, + username: basicSourceSecretUsername, + }); + + cy.log('Edit secret'); + detailsPage.clickPageActionFromDropdown('Edit Secret'); + cy.byTestID('secret-username').clear(); + cy.byTestID('secret-username').type(basicSourceSecretUsernameUpdated); + cy.byTestID('secret-password').clear(); + cy.byTestID('secret-password').type(basicSourceSecretPasswordUpdated); + secrets.save(); + + cy.log('Verify edit'); + secrets.detailsPageIsLoaded(basicSourceSecretName); + secrets.checkSecret({ + password: basicSourceSecretPasswordUpdated, + username: basicSourceSecretUsernameUpdated, + }); + + cy.log('Delete secret'); + secrets.deleteSecret(basicSourceSecretName); + }); + + it(`Creates, edits, and deletes a SSH source secret`, () => { + cy.log('Create secret'); + cy.get('.co-m-pane__heading').contains('Create source secret'); + secrets.enterSecretName(sshSourceSecretName); + cy.byLegacyTestID('dropdown-button').click(); + cy.byTestDropDownMenu('kubernetes.io/ssh-auth').click(); + cy.byLegacyTestID('file-input-textarea').type(sshSourceSecretSSHKey); + secrets.save(); + secrets.detailsPageIsLoaded(sshSourceSecretName); + + cy.log('Verify secret'); + secrets.checkSecret({ + 'ssh-privatekey': `${sshSourceSecretSSHKey}\n`, + }); + + cy.log('Edit secret'); + detailsPage.clickPageActionFromDropdown('Edit Secret'); + cy.byLegacyTestID('file-input-textarea').clear(); + cy.byLegacyTestID('file-input-textarea').type(sshSourceSecretSSHKeUpdated); + secrets.save(); + + cy.log('Verify edit'); + secrets.detailsPageIsLoaded(sshSourceSecretName); + secrets.checkSecret({ + 'ssh-privatekey': `${sshSourceSecretSSHKeUpdated}\n`, + }); + + cy.log('Delete secret'); + secrets.deleteSecret(sshSourceSecretName); + }); +}); diff --git a/frontend/packages/integration-tests-cypress/tests/crud/secrets/webhook.cy.ts b/frontend/packages/integration-tests-cypress/tests/crud/secrets/webhook.cy.ts new file mode 100644 index 000000000000..5ffe40ebc031 --- /dev/null +++ b/frontend/packages/integration-tests-cypress/tests/crud/secrets/webhook.cy.ts @@ -0,0 +1,56 @@ +import { checkErrors, testName } from '../../../support'; +import { detailsPage } from '../../../views/details-page'; +import { secrets } from '../../../views/secret'; + +describe('Webhook secret', () => { + const webhookSecretName = `webhook-secret-${testName}`; + const webhookSecretKey = 'webhookValue'; + + before(() => { + cy.login(); + cy.createProjectWithCLI(testName); + }); + + beforeEach(() => { + cy.visit(`/k8s/ns/${testName}/secrets/`); + secrets.clickCreateSecretDropdownButton('webhook'); + }); + + afterEach(() => { + checkErrors(); + }); + + after(() => { + cy.deleteProjectWithCLI(testName); + }); + + it(`Create, edit, and delete a webhook secret`, () => { + cy.log('Create secret'); + cy.get('.co-m-pane__heading').contains('Create webhook secret'); + secrets.enterSecretName(webhookSecretName); + cy.byTestID('secret-key').type(webhookSecretKey); + secrets.save(); + secrets.detailsPageIsLoaded(webhookSecretName); + + cy.log('Verify secret'); + secrets.checkSecret({ + WebHookSecretKey: webhookSecretKey, + }); + + cy.log('Edit secret'); + detailsPage.clickPageActionFromDropdown('Edit Secret'); + cy.byTestID('webhook-generate-button').click(); + secrets.save(); + + cy.log('Verify edit'); + secrets.detailsPageIsLoaded(webhookSecretName); + secrets.clickRevealValues(); + cy.get('.co-copy-to-clipboard__text .pf-c-code-block__code') + .eq(0) + .invoke('text') + .should('not.equal', webhookSecretKey); + + cy.log('Delete secret'); + secrets.deleteSecret(webhookSecretName); + }); +}); diff --git a/frontend/packages/integration-tests-cypress/tsconfig.json b/frontend/packages/integration-tests-cypress/tsconfig.json index 7f7414efbab9..0d0b77d6e0c6 100644 --- a/frontend/packages/integration-tests-cypress/tsconfig.json +++ b/frontend/packages/integration-tests-cypress/tsconfig.json @@ -1,9 +1,7 @@ - { "compilerOptions": { - "types": ["cypress"] + "types": ["cypress"], + "jsx": "react" }, - "include": [ - "../../node_modules/cypress", "**/*.ts" - ] + "include": ["../../node_modules/cypress", "**/*.ts"] } diff --git a/frontend/packages/integration-tests-cypress/views/alertmanager.ts b/frontend/packages/integration-tests-cypress/views/alertmanager.ts new file mode 100644 index 000000000000..5990ef16d3e3 --- /dev/null +++ b/frontend/packages/integration-tests-cypress/views/alertmanager.ts @@ -0,0 +1,90 @@ +import { Base64 } from 'js-base64'; +import { safeLoad } from 'js-yaml'; +import * as _ from 'lodash'; +import { + AlertmanagerConfig, + AlertmanagerReceiver, +} from '@console/internal/components/monitoring/alertmanager/alertmanager-config'; +import { detailsPage } from './details-page'; +import { listPage } from './list-page'; +import * as yamlEditor from './yaml-editor'; + +const defaultAlertmanagerYaml = Base64.encode(`"global": + "resolve_timeout": "5m" +"inhibit_rules": +- "equal": + - "namespace" + - "alertname" + "source_match": + "severity": "critical" + "target_match_re": + "severity": "warning|info" +- "equal": + - "namespace" + - "alertname" + "source_match": + "severity": "warning" + "target_match_re": + "severity": "info" +"receivers": +- "name": "Default" +- "name": "Watchdog" +- "name": "Critical" +"route": + "group_by": + - "namespace" + "group_interval": "5m" + "group_wait": "30s" + "receiver": "Default" + "repeat_interval": "12h" + "routes": + - "match": + "alertname": "Watchdog" + "receiver": "Watchdog" + - "match": + "severity": "critical" + "receiver": "Critical"`); + +export const getGlobalsAndReceiverConfig = (name: string, configName: string, content: string) => { + const config: AlertmanagerConfig = safeLoad(content); + const receiverConfig: AlertmanagerReceiver | undefined = _.find(config.receivers, { + name, + }); + return { + globals: config.global, + receiverConfig: receiverConfig?.[configName][0], + }; +}; + +export const alertmanager = { + createReceiver: (receiverName: string, configs: string) => { + alertmanager.visitAlertmanagerPage(); + cy.byLegacyTestID('create-receiver').click(); + cy.byLegacyTestID('receiver-name').type(receiverName); + cy.byLegacyTestID('dropdown-button').click(); + cy.get(`[data-test-dropdown-menu=${configs}]`).click(); + }, + reset: () => + cy.exec( + `kubectl patch secret 'alertmanager-main' -n 'openshift-monitoring' --type='json' -p='[{ op: 'replace', path: '/data/alertmanager.yaml', value: ${defaultAlertmanagerYaml}}]'`, + ), + save: () => cy.byLegacyTestID('save-changes').should('be.enabled').click(), + showAdvancedConfiguration: () => cy.get('button.pf-c-expandable-section__toggle').click(), + validateCreation: (receiverName: string, type: string, severity: string, warning: string) => { + cy.byLegacyTestID('item-filter').clear(); + cy.byLegacyTestID('item-filter').type(receiverName); + listPage.rows.shouldExist(receiverName); + listPage.rows.shouldExist(type); + listPage.rows.shouldExist(`${severity}=${warning}`); + }, + visitAlertmanagerPage: () => { + cy.visit('/monitoring/alertmanagerconfig'); + }, + visitEditPage: (receiverName: string) => { + cy.visit(`/monitoring/alertmanagerconfig/receivers/${receiverName}/edit`); + }, + visitYAMLPage: () => { + detailsPage.selectTab('yaml'); + yamlEditor.isLoaded(); + }, +}; 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'); + }, +}; diff --git a/frontend/packages/integration-tests-cypress/views/secret.ts b/frontend/packages/integration-tests-cypress/views/secret.ts index 887b07fa5c1b..5e863f58216a 100644 --- a/frontend/packages/integration-tests-cypress/views/secret.ts +++ b/frontend/packages/integration-tests-cypress/views/secret.ts @@ -1,12 +1,66 @@ +import { Base64 } from 'js-base64'; +import { detailsPage } from './details-page'; +import { listPage } from './list-page'; +import { modal } from './modal'; + export const secrets = { - clickCreateKeyValSecretDropdownButton: () => { + addSecretToWorkload: (resourceName: string) => { + cy.byTestID('Add Secret to workload').click(); + modal.shouldBeOpened(); + modal.modalTitleShouldContain('Add secret to workload'); + cy.get('#co-add-secret-to-workload__workload').click(); + cy.byLegacyTestID('dropdown-text-filter').type(resourceName); + cy.byTestID('dropdown-menu-item-link').click(); + }, + checkSecret: (keyValuesToCheck: object, jsonOutput: boolean = false) => { + secrets.clickRevealValues(); + const renderedKeyValues = {}; + cy.byTestID('secret-data') + .find('[data-test="secret-data-term"]') + .each(($el, index) => { + const key = $el.text(); + cy.get('[data-test="copy-to-clipboard"]') + .eq(index) + .invoke('text') + .then(($text) => { + renderedKeyValues[key] = jsonOutput ? JSON.parse($text) : $text; + }); + }) + .then(() => { + expect(renderedKeyValues).toEqual(keyValuesToCheck); + }); + }, + clickAddCredentialsButton: () => cy.byTestID('add-credentials-button').click(), + clickRemoveEntryButton: () => cy.byTestID('remove-entry-button').first().click(), + clickRevealValues: () => { + cy.byTestID('reveal-values').click(); + }, + clickCreateSecretDropdownButton: (secretType: string) => { cy.byTestID('item-create') .click() .get('body') .then(($body) => { - if ($body.find(`[data-test-dropdown-menu="generic"]`).length) { - cy.get(`[data-test-dropdown-menu="generic"]`).click(); + if ($body.find(`[data-test-dropdown-menu=${secretType}]`).length) { + cy.get(`[data-test-dropdown-menu=${secretType}]`).click(); } }); }, + deleteSecret: (secretName: string) => { + detailsPage.clickPageActionFromDropdown('Delete Secret'); + modal.shouldBeOpened(); + modal.submit(); + modal.shouldBeClosed(); + listPage.rows.shouldNotExist(secretName); + }, + detailsPageIsLoaded: (secretName: string) => { + cy.byTestID('loading-indicator').should('not.exist'); + detailsPage.isLoaded(); + detailsPage.titleShouldContain(secretName); + }, + encode: (username, password) => Base64.encode(`${username}:${password}`), + enterSecretName: (secretName: string) => cy.byTestID('secret-name').type(secretName), + getResourceJSON: (name: string, namespace: string, kind: string) => { + return cy.exec(`kubectl get -o json -n ${namespace} ${kind} ${name}`); + }, + save: () => cy.byTestID('save-changes').click(), }; diff --git a/frontend/public/components/configmap-and-secret-data.tsx b/frontend/public/components/configmap-and-secret-data.tsx index 8cb790fd1c9f..fa191694cc81 100644 --- a/frontend/public/components/configmap-and-secret-data.tsx +++ b/frontend/public/components/configmap-and-secret-data.tsx @@ -107,7 +107,7 @@ export const SecretData: React.FC = ({ data, title }) => { .sort() .forEach((k) => { dl.push( -
+
{k}
, ); @@ -131,6 +131,7 @@ export const SecretData: React.FC = ({ data, title }) => { onClick={() => setReveal(!reveal)} variant="link" className="pf-m-link--align-right" + data-test="reveal-values" > {reveal ? ( <> @@ -146,7 +147,7 @@ export const SecretData: React.FC = ({ data, title }) => { ) : null} - {dl.length ?
{dl}
: } + {dl.length ?
{dl}
: } ); }; diff --git a/frontend/public/components/modals/add-secret-to-workload.tsx b/frontend/public/components/modals/add-secret-to-workload.tsx index 06329325230d..ef6f523c8cf6 100644 --- a/frontend/public/components/modals/add-secret-to-workload.tsx +++ b/frontend/public/components/modals/add-secret-to-workload.tsx @@ -187,6 +187,7 @@ export const AddSecretToWorkloadModal: React.FC = autocompleteFilter={autocompleteFilter} autocompletePlaceholder={selectWorkloadPlaceholder} id="co-add-secret-to-workload__workload" + data-test="add-secret-to-workload-button" />
@@ -207,6 +208,7 @@ export const AddSecretToWorkloadModal: React.FC = className="pf-c-form-control" name="prefix" id="co-add-secret-to-workload__prefix" + data-test="add-secret-to-workload-prefix" placeholder="(optional)" type="text" onChange={(e) => setPrefix(e.currentTarget.value)} @@ -232,6 +234,7 @@ export const AddSecretToWorkloadModal: React.FC = className="pf-c-form-control" name="mountPath" id="co-add-secret-to-workload__mountpath" + data-test="add-secret-to-workload-mountpath" type="text" onChange={(e) => setMountPath(e.currentTarget.value)} required diff --git a/frontend/public/components/monitoring/alertmanager/alertmanager-config.tsx b/frontend/public/components/monitoring/alertmanager/alertmanager-config.tsx index e0a0dbfbfa9a..5c453419aede 100644 --- a/frontend/public/components/monitoring/alertmanager/alertmanager-config.tsx +++ b/frontend/public/components/monitoring/alertmanager/alertmanager-config.tsx @@ -51,6 +51,7 @@ const AlertRouting = ({ secret, config }: AlertRoutingProps) => { className="co-alert-manager-config__edit-alert-routing-btn" onClick={() => createAlertRoutingModal({ config, secret })} variant="secondary" + data-test="edit-alert-routing-btn" > {t('public~Edit')} diff --git a/frontend/public/components/monitoring/alertmanager/alertmanager-page.tsx b/frontend/public/components/monitoring/alertmanager/alertmanager-page.tsx index 8890d38654a5..d358cdbcbf35 100644 --- a/frontend/public/components/monitoring/alertmanager/alertmanager-page.tsx +++ b/frontend/public/components/monitoring/alertmanager/alertmanager-page.tsx @@ -45,14 +45,18 @@ const AlertmanagerPage: React.FC<{ match: { url: string } }> = ({ match }) => { 'co-m-horizontal-nav-item--active': url === configPath, })} > - {t('public~Details')} + + {t('public~Details')} +
  • - {t('public~YAML')} + + {t('public~YAML')} +
  • diff --git a/frontend/public/components/secrets/create-secret.tsx b/frontend/public/components/secrets/create-secret.tsx index 3b986f995b1d..8f766de91299 100644 --- a/frontend/public/components/secrets/create-secret.tsx +++ b/frontend/public/components/secrets/create-secret.tsx @@ -693,7 +693,12 @@ class CreateConfigSubformWithTranslation extends React.Component<
    {_.size(this.state.secretEntriesArray) > 1 && (
    - @@ -711,6 +716,7 @@ class CreateConfigSubformWithTranslation extends React.Component< onClick={() => this.addEntry()} type="button" variant="link" + data-test="add-credentials-button" > {t('public~Add credentials')} @@ -819,6 +825,7 @@ class WebHookSecretFormWithTranslation extends React.Component< {t('public~Generate')} @@ -943,6 +951,7 @@ class BasicAuthSubformWithTranslation extends React.Component< {_.size(this.state.secretEntriesArray) > 1 && (
    - @@ -1182,6 +1197,7 @@ class GenericSecretFormWithTranslation extends React.Component< onClick={() => this.addEntry()} type="button" variant="link" + data-test="add-credentials-button" > {t('public~Add key/value')} diff --git a/frontend/public/components/utils/headings.tsx b/frontend/public/components/utils/headings.tsx index dc01a193bf02..2fc503141d68 100644 --- a/frontend/public/components/utils/headings.tsx +++ b/frontend/public/components/utils/headings.tsx @@ -86,6 +86,7 @@ export const ActionButtons: React.SFC = ({ actionButtons }) variant="primary" onClick={actionButton.callback} key={i} + data-test={actionButton.label} > {actionButton.label}