mirror of https://github.com/rancher/dashboard.git
Merge pull request #13152 from yonasberhe23/services_tests_e2e
automation: services - external name tests
This commit is contained in:
commit
4b836a4d49
|
|
@ -0,0 +1,23 @@
|
|||
import ComponentPo from '@/cypress/e2e/po/components/component.po';
|
||||
|
||||
export class GrowlManagerPo extends ComponentPo {
|
||||
constructor() {
|
||||
super('.growl-container');
|
||||
}
|
||||
|
||||
growlList() {
|
||||
return this.self().find('.growl-list');
|
||||
}
|
||||
|
||||
growlMessage() {
|
||||
return this.self().find('.growl-message');
|
||||
}
|
||||
|
||||
dismissWarning() {
|
||||
return this.self().find('.icon-close').click();
|
||||
}
|
||||
|
||||
dismissAllWarnings() {
|
||||
return this.self().find('button.btn').contains('Clear All Notifications').click();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import ComponentPo from '@/cypress/e2e/po/components/component.po';
|
||||
|
||||
export default class KeyValuePo extends ComponentPo {
|
||||
addButton(label: string) {
|
||||
return this.self().find('[data-testid="add_row_item_button"]').contains(label);
|
||||
}
|
||||
|
||||
setKeyValueAtIndex(label: string, key: string, value: string, index: number, selector: string) {
|
||||
this.addButton(label).click();
|
||||
this.self().find(`${ selector } [data-testid="input-kv-item-key-${ index }"]`).type(key);
|
||||
this.self().find(`${ selector } [data-testid="kv-item-value-${ index }"]`).type(value);
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,10 @@ export default class TabbedPo extends ComponentPo {
|
|||
return this.self().get('[data-testid="tabbed-block"] > li');
|
||||
}
|
||||
|
||||
assertTabIsActive(selector: string) {
|
||||
return this.self().find(`${ selector }`).should('have.class', 'active');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tab labels
|
||||
* @param tabLabelsSelector
|
||||
|
|
|
|||
|
|
@ -4,14 +4,26 @@ import CruResourcePo from '@/cypress/e2e/po/components/cru-resource.po';
|
|||
import ResourceYamlPo from '@/cypress/e2e/po/components/resource-yaml.po';
|
||||
|
||||
export default class ResourceDetailPo extends ComponentPo {
|
||||
/**
|
||||
* components for handling CRUD operations for resources, including cancel/save buttons
|
||||
* @returns
|
||||
*/
|
||||
cruResource() {
|
||||
return new CruResourcePo(this.self());
|
||||
}
|
||||
|
||||
/**
|
||||
* components for managing the resource creation and edit forms
|
||||
* @returns
|
||||
*/
|
||||
createEditView() {
|
||||
return new CreateEditViewPo(this.self());
|
||||
}
|
||||
|
||||
/**
|
||||
* components for YAML editor
|
||||
* @returns
|
||||
*/
|
||||
resourceYaml() {
|
||||
return new ResourceYamlPo(this.self());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,76 @@
|
|||
import PagePo from '@/cypress/e2e/po/pages/page.po';
|
||||
import NameNsDescription from '@/cypress/e2e/po/components/name-ns-description.po';
|
||||
import ResourceDetailPo from '@/cypress/e2e/po/edit/resource-detail.po';
|
||||
import LabeledSelectPo from '@/cypress/e2e/po/components/labeled-select.po';
|
||||
import TabbedPo from '@/cypress/e2e/po/components/tabbed.po';
|
||||
import LabeledInputPo from '@/cypress/e2e/po/components/labeled-input.po';
|
||||
import ArrayListPo from '@/cypress/e2e/po/components/array-list.po';
|
||||
import KeyValuePo from '@/cypress/e2e/po/components/key-value.po';
|
||||
|
||||
export default class WorkloadsCreateEditPo extends PagePo {
|
||||
private static createPath(clusterId: string, id?: string ) {
|
||||
const root = `/c/${ clusterId }/explorer/storage.k8s.io.storageclass/create`;
|
||||
export default class ServicesCreateEditPo extends PagePo {
|
||||
private static createPath(clusterId: string, namespace?: string, id?: string ) {
|
||||
const root = `/c/${ clusterId }/explorer/service`;
|
||||
|
||||
return id ? `${ root }/${ id }` : `${ root }/create`;
|
||||
return id ? `${ root }/${ namespace }/${ id }` : `${ root }/create`;
|
||||
}
|
||||
|
||||
static goTo(path: string): Cypress.Chainable<Cypress.AUTWindow> {
|
||||
throw new Error('invalid');
|
||||
}
|
||||
|
||||
constructor(clusterId = '_', id?: string) {
|
||||
super(WorkloadsCreateEditPo.createPath(clusterId, id));
|
||||
constructor(clusterId = 'local', namespace?: string, id?: string) {
|
||||
super(ServicesCreateEditPo.createPath(clusterId, namespace, id));
|
||||
}
|
||||
|
||||
resourceDetail() {
|
||||
return new ResourceDetailPo(this.self());
|
||||
}
|
||||
|
||||
title() {
|
||||
return this.self().get('.title .primaryheader h1');
|
||||
}
|
||||
|
||||
nameNsDescription() {
|
||||
return new NameNsDescription(this.self());
|
||||
}
|
||||
|
||||
selectNamespace(label: string) {
|
||||
const selectNs = new LabeledSelectPo(`[data-testid="name-ns-description-namespace"]`, this.self());
|
||||
|
||||
selectNs.toggle();
|
||||
selectNs.clickLabel(label);
|
||||
}
|
||||
|
||||
selectServiceOption(index: number) {
|
||||
return this.resourceDetail().cruResource().selectSubTypeByIndex(index).click();
|
||||
}
|
||||
|
||||
tabs() {
|
||||
return new TabbedPo('[data-testid="tabbed"]');
|
||||
}
|
||||
|
||||
externalNameTab() {
|
||||
return this.tabs().clickTabWithSelector('[data-testid="define-external-name"]');
|
||||
}
|
||||
|
||||
externalNameInput() {
|
||||
return new LabeledInputPo('#define-external-name .labeled-input input');
|
||||
}
|
||||
|
||||
ipAddressesTab() {
|
||||
return this.tabs().clickTabWithSelector('[data-testid="ips"]');
|
||||
}
|
||||
|
||||
ipAddressList() {
|
||||
return new ArrayListPo('section#ips');
|
||||
}
|
||||
|
||||
lablesAnnotationsTab() {
|
||||
return this.tabs().clickTabWithSelector('[data-testid="btn-labels-and-annotations"]');
|
||||
}
|
||||
|
||||
lablesAnnotationsKeyValue() {
|
||||
return new KeyValuePo('section#labels-and-annotations');
|
||||
}
|
||||
|
||||
errorBanner() {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ export class ServicesPagePo extends PagePo {
|
|||
sideNav.navToSideMenuEntryByLabel('Service');
|
||||
}
|
||||
|
||||
constructor(clusterId = 'local') {
|
||||
constructor(private clusterId = 'local') {
|
||||
super(ServicesPagePo.createPath(clusterId));
|
||||
}
|
||||
|
||||
|
|
@ -38,7 +38,7 @@ export class ServicesPagePo extends PagePo {
|
|||
return this.list().masthead().create();
|
||||
}
|
||||
|
||||
createServicesForm(id? : string): ServicesCreateEditPo {
|
||||
return new ServicesCreateEditPo(id);
|
||||
createServicesForm(namespace?: string, id?: string): ServicesCreateEditPo {
|
||||
return new ServicesCreateEditPo(this.clusterId, namespace, id);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ export default class ExtensionsPagePo extends PagePo {
|
|||
return this.title().should('contain', 'Extensions');
|
||||
}
|
||||
|
||||
loading(options: any) {
|
||||
loading() {
|
||||
return this.self().get('.data-loading');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export class HomeLinksPagePo extends RootClusterPage {
|
|||
}
|
||||
|
||||
addLinkButton() {
|
||||
return cy.getId('add_link_button');
|
||||
return cy.getId('add_row_item_button');
|
||||
}
|
||||
|
||||
removeLinkButton() {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,147 @@
|
|||
import { ServicesPagePo } from '@/cypress/e2e/po/pages/explorer/services.po';
|
||||
import { generateServicesDataSmall, servicesNoData } from '@/cypress/e2e/blueprints/explorer/workloads/service-discovery/services-get';
|
||||
import ClusterDashboardPagePo from '@/cypress/e2e/po/pages/explorer/cluster-dashboard.po';
|
||||
import PromptRemove from '@/cypress/e2e/po/prompts/promptRemove.po';
|
||||
import { GrowlManagerPo } from '@/cypress/e2e/po/components/growl-manager.po';
|
||||
|
||||
const cluster = 'local';
|
||||
const servicesPagePo = new ServicesPagePo();
|
||||
const growlPo = new GrowlManagerPo();
|
||||
const cluster = 'local';
|
||||
let serviceExternalName = '';
|
||||
const namespace = 'default';
|
||||
let removeServices = false;
|
||||
const servicesToDelete = [];
|
||||
|
||||
describe('Services', { testIsolation: 'off', tags: ['@explorer', '@adminUser'] }, () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
cy.createE2EResourceName('serviceexternalname').then((name) => {
|
||||
serviceExternalName = name;
|
||||
});
|
||||
});
|
||||
|
||||
describe('CRUD', () => {
|
||||
it('can create an ExternalName Service', () => {
|
||||
cy.intercept('POST', '/v1/services').as('createService');
|
||||
ServicesPagePo.navTo();
|
||||
servicesPagePo.waitForPage();
|
||||
servicesPagePo.clickCreate();
|
||||
servicesPagePo.createServicesForm().waitForPage();
|
||||
|
||||
servicesPagePo.createServicesForm().selectServiceOption(1);
|
||||
servicesPagePo.createServicesForm().waitForPage(null, 'define-external-name');
|
||||
servicesPagePo.createServicesForm().resourceDetail().title().should('contain', 'Create ExternalName');
|
||||
servicesPagePo.createServicesForm().nameNsDescription().name().set(serviceExternalName);
|
||||
servicesPagePo.createServicesForm().nameNsDescription().description().set(`${ serviceExternalName }-desc`);
|
||||
servicesPagePo.createServicesForm().selectNamespace(namespace);
|
||||
servicesPagePo.createServicesForm().tabs().allTabs().should('have.length', 3);
|
||||
|
||||
const tabs = ['External Name', 'IP Addresses', 'Labels & Annotations'];
|
||||
|
||||
servicesPagePo.createServicesForm().tabs().tabNames().each((el, i) => {
|
||||
expect(el).to.eq(tabs[i]);
|
||||
});
|
||||
|
||||
servicesPagePo.createServicesForm().tabs().assertTabIsActive('[data-testid="define-external-name"]');
|
||||
servicesPagePo.createServicesForm().externalNameInput().set('my.database.example.com');
|
||||
servicesPagePo.createServicesForm().ipAddressesTab();
|
||||
servicesPagePo.createServicesForm().waitForPage(null, 'ips');
|
||||
servicesPagePo.createServicesForm().ipAddressList().setValueAtIndex('1.1.1.1', 0);
|
||||
servicesPagePo.createServicesForm().ipAddressList().setValueAtIndex('2.2.2.2', 1);
|
||||
servicesPagePo.createServicesForm().lablesAnnotationsTab();
|
||||
servicesPagePo.createServicesForm().waitForPage(null, 'labels-and-annotations');
|
||||
servicesPagePo.createServicesForm().lablesAnnotationsKeyValue().setKeyValueAtIndex('Add Label', 'label-key1', 'label-value1', 0, '.labels-and-annotations-container div.row:nth-of-type(2)');
|
||||
|
||||
// Adding Annotations doesn't work via test automation
|
||||
// See https://github.com/rancher/dashboard/issues/13191
|
||||
// servicesPagePo.createServicesForm().lablesAnnotationsKeyValue().setKeyValueAtIndex('Add Annotation', 'ann-key1', 'ann-value1', 0, '.labels-and-annotations-container div.row:nth-of-type(3)');
|
||||
servicesPagePo.createServicesForm().resourceDetail().createEditView().create();
|
||||
cy.wait('@createService').then(({ response }) => {
|
||||
expect(response?.statusCode).to.eq(201);
|
||||
removeServices = true;
|
||||
servicesToDelete.push(`${ namespace }/${ serviceExternalName }`);
|
||||
});
|
||||
servicesPagePo.waitForPage();
|
||||
servicesPagePo.list().resourceTable().sortableTable().rowWithName(serviceExternalName)
|
||||
.checkVisible();
|
||||
growlPo.dismissWarning();
|
||||
});
|
||||
|
||||
it('can edit an ExternalName Service', () => {
|
||||
ServicesPagePo.navTo();
|
||||
servicesPagePo.waitForPage();
|
||||
servicesPagePo.list().actionMenu(serviceExternalName).getMenuItem('Edit Config').click();
|
||||
servicesPagePo.createServicesForm(namespace, serviceExternalName).waitForPage('mode=edit', 'define-external-name');
|
||||
servicesPagePo.createServicesForm().nameNsDescription().description().set(`${ serviceExternalName }-desc`);
|
||||
servicesPagePo.createServicesForm().resourceDetail().cruResource().saveAndWaitForRequests('PUT', `/v1/services/${ namespace }/${ serviceExternalName }`)
|
||||
.then(({ response }) => {
|
||||
expect(response?.statusCode).to.eq(200);
|
||||
expect(response?.body.metadata).to.have.property('name', serviceExternalName);
|
||||
expect(response?.body.metadata.annotations).to.have.property('field.cattle.io/description', `${ serviceExternalName }-desc`);
|
||||
});
|
||||
servicesPagePo.waitForPage();
|
||||
growlPo.dismissWarning();
|
||||
});
|
||||
|
||||
it('can clone an ExternalName Service', () => {
|
||||
ServicesPagePo.navTo();
|
||||
servicesPagePo.waitForPage();
|
||||
servicesPagePo.list().actionMenu(serviceExternalName).getMenuItem('Clone').click();
|
||||
servicesPagePo.createServicesForm(namespace, serviceExternalName).waitForPage('mode=clone', 'define-external-name');
|
||||
servicesPagePo.createServicesForm().nameNsDescription().name().set(`clone-${ serviceExternalName }`);
|
||||
servicesPagePo.createServicesForm().resourceDetail().cruResource().saveAndWaitForRequests('POST', '/v1/services')
|
||||
.then(({ response }) => {
|
||||
expect(response?.statusCode).to.eq(201);
|
||||
expect(response?.body.metadata).to.have.property('name', `clone-${ serviceExternalName }`);
|
||||
removeServices = true;
|
||||
servicesToDelete.push(`${ namespace }/clone-${ serviceExternalName }`);
|
||||
});
|
||||
servicesPagePo.waitForPage();
|
||||
servicesPagePo.list().resourceTable().sortableTable().rowWithName(`clone-${ serviceExternalName }`)
|
||||
.checkVisible();
|
||||
growlPo.dismissWarning();
|
||||
});
|
||||
|
||||
it('can Edit Yaml', () => {
|
||||
ServicesPagePo.navTo();
|
||||
servicesPagePo.waitForPage();
|
||||
servicesPagePo.list().actionMenu(`clone-${ serviceExternalName }`).getMenuItem('Edit YAML').click();
|
||||
servicesPagePo.createServicesForm(namespace, `clone-${ serviceExternalName }`).waitForPage('mode=edit&as=yaml');
|
||||
servicesPagePo.createServicesForm().title().contains(`Service: clone-${ serviceExternalName }`).should('be.visible');
|
||||
});
|
||||
|
||||
it('can delete an ExternalName Service', () => {
|
||||
ServicesPagePo.navTo();
|
||||
servicesPagePo.waitForPage();
|
||||
servicesPagePo.list().actionMenu(`clone-${ serviceExternalName }`).getMenuItem('Delete').click();
|
||||
servicesPagePo.list().resourceTable().sortableTable().rowNames('.col-link-detail')
|
||||
.then((rows: any) => {
|
||||
const promptRemove = new PromptRemove();
|
||||
|
||||
cy.intercept('DELETE', `/v1/services/${ namespace }/clone-${ serviceExternalName }`).as('deleteService');
|
||||
|
||||
promptRemove.remove();
|
||||
cy.wait('@deleteService');
|
||||
servicesPagePo.waitForPage();
|
||||
servicesPagePo.list().resourceTable().sortableTable().checkRowCount(false, rows.length - 1);
|
||||
servicesPagePo.list().resourceTable().sortableTable().rowNames('.col-link-detail')
|
||||
.should('not.contain', `clone-${ serviceExternalName }`);
|
||||
});
|
||||
});
|
||||
|
||||
// testing https://github.com/rancher/dashboard/issues/11889
|
||||
it('validation errors should not be shown when form is just opened', () => {
|
||||
servicesPagePo.goTo();
|
||||
servicesPagePo.clickCreate();
|
||||
servicesPagePo.createServicesForm().errorBanner().should('not.exist');
|
||||
});
|
||||
|
||||
after(() => {
|
||||
if (removeServices) {
|
||||
// delete gitrepo
|
||||
servicesToDelete.forEach((r) => cy.deleteRancherResource('v1', 'services', r, false));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('List', { tags: ['@vai', '@adminUser'] }, () => {
|
||||
|
|
@ -84,12 +218,6 @@ describe('Services', { testIsolation: 'off', tags: ['@explorer', '@adminUser'] }
|
|||
servicesPagePo.list().resourceTable().sortableTable().checkRowCount(false, 3);
|
||||
});
|
||||
|
||||
it('validation errors should not be shown when form is just opened', () => {
|
||||
servicesPagePo.goTo();
|
||||
servicesPagePo.clickCreate();
|
||||
servicesPagePo.createServicesForm().errorBanner().should('not.exist');
|
||||
});
|
||||
|
||||
after('clean up', () => {
|
||||
cy.updateNamespaceFilter(cluster, 'none', '{"local":["all://user"]}');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -195,6 +195,7 @@ describe('Extensions page', { tags: ['@extensions', '@adminUser'] }, () => {
|
|||
// Ensure that the banner should be shown (by confirming that a required repo isn't there)
|
||||
appRepoList.goTo();
|
||||
appRepoList.waitForPage();
|
||||
appRepoList.sortableTable().checkLoadingIndicatorNotVisible();
|
||||
appRepoList.sortableTable().noRowsShouldNotExist();
|
||||
appRepoList.sortableTable().rowNames().then((names: any) => {
|
||||
if (names.includes(UI_PLUGINS_PARTNERS_REPO_NAME)) {
|
||||
|
|
@ -409,6 +410,7 @@ describe('Extensions page', { tags: ['@extensions', '@adminUser'] }, () => {
|
|||
|
||||
extensionsPo.extensionTabAvailableClick();
|
||||
extensionsPo.waitForPage(null, 'available');
|
||||
extensionsPo.loading().should('not.exist');
|
||||
|
||||
// Install unauthenticated extension
|
||||
extensionsPo.extensionCardInstallClick(UNAUTHENTICATED_EXTENSION_NAME);
|
||||
|
|
@ -418,6 +420,8 @@ describe('Extensions page', { tags: ['@extensions', '@adminUser'] }, () => {
|
|||
// let's check the extension reload banner and reload the page
|
||||
extensionsPo.extensionReloadBanner().should('be.visible');
|
||||
extensionsPo.extensionReloadClick();
|
||||
extensionsPo.waitForPage(null, 'installed');
|
||||
extensionsPo.loading().should('not.exist');
|
||||
|
||||
// make sure both extensions have been imported
|
||||
extensionsPo.extensionScriptImport(UNAUTHENTICATED_EXTENSION_NAME).should('exist');
|
||||
|
|
@ -436,7 +440,8 @@ describe('Extensions page', { tags: ['@extensions', '@adminUser'] }, () => {
|
|||
// make sure both extensions have been imported after logging in again
|
||||
cy.login(undefined, undefined, false);
|
||||
extensionsPo.goTo();
|
||||
extensionsPo.waitForPage();
|
||||
extensionsPo.waitForPage(null, 'installed');
|
||||
extensionsPo.loading().should('not.exist');
|
||||
extensionsPo.waitForTitle();
|
||||
extensionsPo.extensionScriptImport(UNAUTHENTICATED_EXTENSION_NAME).should('exist');
|
||||
extensionsPo.extensionScriptImport(EXTENSION_NAME).should('exist');
|
||||
|
|
|
|||
|
|
@ -798,7 +798,7 @@ export default {
|
|||
v-if="addAllowed"
|
||||
type="button"
|
||||
class="btn role-tertiary add"
|
||||
data-testid="add_link_button"
|
||||
data-testid="add_row_item_button"
|
||||
:disabled="loading || disabled || (keyOptions && filteredKeyOptions.length === 0)"
|
||||
@click="add()"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ describe('component: KeyValue', () => {
|
|||
expect(secondKeyInput.exists()).toBe(false);
|
||||
expect(secondValueInput.exists()).toBe(false);
|
||||
|
||||
const addButton = wrapper.find('[data-testid="add_link_button"]');
|
||||
const addButton = wrapper.find('[data-testid="add_row_item_button"]');
|
||||
|
||||
addButton.trigger('click');
|
||||
await nextTick();
|
||||
|
|
|
|||
Loading…
Reference in New Issue