From ff065e508e2bcf34229f33b8623c8e443034805e Mon Sep 17 00:00:00 2001 From: Richard Cox Date: Fri, 21 Jul 2023 11:15:03 +0100 Subject: [PATCH] Beef up flaky extension banner test - banner should be visibile when test starts - banner is visible if v3 setting is not 'true' and there is a missing helm repo - previously confirmed the repo is missing, now confirm the v3 setting is correct - split rancher api commands out from base commands, added get/set commands --- cypress/e2e/tests/pages/extensions.spec.ts | 16 ++++ cypress/globals.d.ts | 5 +- cypress/support/commands/commands.ts | 52 ++++++++++++ .../rancher-api-commands.ts} | 84 ++++++++----------- cypress/support/e2e.ts | 3 +- 5 files changed, 111 insertions(+), 49 deletions(-) create mode 100644 cypress/support/commands/commands.ts rename cypress/support/{commands.ts => commands/rancher-api-commands.ts} (79%) diff --git a/cypress/e2e/tests/pages/extensions.spec.ts b/cypress/e2e/tests/pages/extensions.spec.ts index d1141645cae..c1d07045c29 100644 --- a/cypress/e2e/tests/pages/extensions.spec.ts +++ b/cypress/e2e/tests/pages/extensions.spec.ts @@ -76,6 +76,22 @@ describe('Extensions page', { tags: '@adminUser' }, () => { }); it('New repos banner should only appear once (after dismiss should NOT appear again)', () => { + cy.getRancherResource('v3', 'setting', 'display-add-extension-repos-banner', null).then((resp: Cypress.Response) => { + const notFound = resp.status === 404; + const requiredValue = resp.body?.value === 'true'; + + if (notFound || requiredValue) { + cy.log('Good test state', '/v3/setting/display-add-extension-repos-banner', resp.status, JSON.stringify(resp?.body || {})); + } else { + cy.log('Bad test state', '/v3/setting/display-add-extension-repos-banner', resp.status, JSON.stringify(resp?.body || {})); + + return cy.setRancherResource('v3', 'setting', 'display-add-extension-repos-banner', { + ...resp.body, + value: 'true' + }); + } + }); + const appRepoList = new ReposListPagePo('local', 'apps'); // Ensure that the banner should be shown (by confirming that a required repo isn't there) diff --git a/cypress/globals.d.ts b/cypress/globals.d.ts index 679e8c370a3..9cdd8c2d069 100644 --- a/cypress/globals.d.ts +++ b/cypress/globals.d.ts @@ -32,7 +32,10 @@ declare namespace Cypress { setGlobalRoleBinding(userId: string, role: string): Chainable; setClusterRoleBinding(clusterId: string, userPrincipalId: string, role: string): Chainable; setProjectRoleBinding(clusterId: string, userPrincipalId: string, projectName: string, role: string): Chainable; - getProject(clusterId: string, projectName: string): Chainable; + getProjectByName(clusterId: string, projectName: string): Chainable; + + getRancherResource(prefix: 'v3' | 'v1', resourceType: string, resourceId: string, expectedStatusCode: string): Chainable; + setRancherResource(prefix: 'v3' | 'v1', resourceType: string, resourceId: string, body: string): Chainable; /** * Wrapper for cy.get() to simply define the data-testid value that allows you to pass a matcher to find the element. diff --git a/cypress/support/commands/commands.ts b/cypress/support/commands/commands.ts new file mode 100644 index 00000000000..23884eae0dd --- /dev/null +++ b/cypress/support/commands/commands.ts @@ -0,0 +1,52 @@ +import { Matcher } from '@/cypress/support/types'; + +/** + * Get input field for given label + */ +Cypress.Commands.add('byLabel', (label) => { + return cy.get('.labeled-input').contains(label).siblings('input'); +}); + +/** + * Wrap the cy.find() command to simplify the selector declaration of the data-testid + */ +Cypress.Commands.add('findId', (id: string, matcher?: Matcher = '') => { + return cy.find(`[data-testid${ matcher }="${ id }"]`); +}); + +/** + * Wrap the cy.get() command to simplify the selector declaration of the data-testid + */ +Cypress.Commands.add('getId', (id: string, matcher?: Matcher = '') => { + return cy.get(`[data-testid${ matcher }="${ id }"]`); +}); + +Cypress.Commands.add('keyboardControls', (triggerKeys: any = {}, count = 1) => { + for (let i = 0; i < count; i++) { + cy.get('body').trigger('keydown', triggerKeys); + } +}); + +/** + * Intercept all requests and return + * @param {array} intercepts - Array of intercepts to return + * return {array} - Array of intercepted request strings + * return {string} - Intercepted request string + */ +Cypress.Commands.add('interceptAllRequests', (method = '/GET/POST/PUT/PATCH/', urls = ['/v1/*']) => { + const interceptedUrls: string[] = urls.map((cUrl, i) => { + cy.intercept(method, cUrl).as(`interceptAllRequests${ i }`); + + return `@interceptAllRequests${ i }`; + }); + + return cy.wrap(interceptedUrls); +}); + +Cypress.Commands.add('iFrame', () => { + return cy + .get('[data-testid="ember-iframe"]', { log: false }) + .its('0.contentDocument.body', { log: false }) + .should('not.be.empty') + .then((body) => cy.wrap(body)); +}); diff --git a/cypress/support/commands.ts b/cypress/support/commands/rancher-api-commands.ts similarity index 79% rename from cypress/support/commands.ts rename to cypress/support/commands/rancher-api-commands.ts index 6973d549cc3..65e788459bd 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands/rancher-api-commands.ts @@ -1,7 +1,9 @@ import { LoginPagePo } from '@/cypress/e2e/po/pages/login-page.po'; -import { Matcher } from '@/cypress/support/types'; import { CreateUserParams } from '@/cypress/globals'; +// This file contains commands which makes API requests to the rancher API. +// It includes the `login` command to store the `token` to use + let token: any; /** @@ -164,7 +166,7 @@ Cypress.Commands.add('setClusterRoleBinding', (clusterId, userPrincipalId, role) * */ Cypress.Commands.add('setProjectRoleBinding', (clusterId, userPrincipalId, projectName, role) => { - return cy.getProject(clusterId, projectName) + return cy.getProjectByName(clusterId, projectName) .then((project: any) => cy.request({ method: 'POST', url: `${ Cypress.env('api') }/v3/projectroletemplatebindings`, @@ -187,7 +189,7 @@ Cypress.Commands.add('setProjectRoleBinding', (clusterId, userPrincipalId, proje /** * Get the project with the given name */ -Cypress.Commands.add('getProject', (clusterId, projectName) => { +Cypress.Commands.add('getProjectByName', (clusterId, projectName) => { return cy.request({ method: 'GET', url: `${ Cypress.env('api') }/v3/projects?name=${ projectName }&clusterId=${ clusterId }`, @@ -204,27 +206,6 @@ Cypress.Commands.add('getProject', (clusterId, projectName) => { }); }); -/** - * Get input field for given label - */ -Cypress.Commands.add('byLabel', (label) => { - return cy.get('.labeled-input').contains(label).siblings('input'); -}); - -/** - * Wrap the cy.find() command to simplify the selector declaration of the data-testid - */ -Cypress.Commands.add('findId', (id: string, matcher?: Matcher = '') => { - return cy.find(`[data-testid${ matcher }="${ id }"]`); -}); - -/** - * Wrap the cy.get() command to simplify the selector declaration of the data-testid - */ -Cypress.Commands.add('getId', (id: string, matcher?: Matcher = '') => { - return cy.get(`[data-testid${ matcher }="${ id }"]`); -}); - /** * Override user preferences to default values, allowing to pass custom preferences for a deterministic scenario */ @@ -271,32 +252,41 @@ Cypress.Commands.add('requestBase64Image', (url: string) => { }); }); -Cypress.Commands.add('keyboardControls', (triggerKeys: any = {}, count = 1) => { - for (let i = 0; i < count; i++) { - cy.get('body').trigger('keydown', triggerKeys); - } -}); - /** - * Intercept all requests and return - * @param {array} intercepts - Array of intercepts to return - * return {array} - Array of intercepted request strings - * return {string} - Intercepted request string + * Get a v3 / v1 resource */ -Cypress.Commands.add('interceptAllRequests', (method = '/GET/POST/PUT/PATCH/', urls = ['/v1/*']) => { - const interceptedUrls: string[] = urls.map((cUrl, i) => { - cy.intercept(method, cUrl).as(`interceptAllRequests${ i }`); - - return `@interceptAllRequests${ i }`; - }); +Cypress.Commands.add('getRancherResource', (prefix, resourceType, resourceId, expectedStatusCode = 200) => { + return cy.request({ + method: 'GET', + url: `${ Cypress.env('api') }/${ prefix }/${ resourceType }/${ resourceId }`, + headers: { + 'x-api-csrf': token.value, + Accept: 'application/json' + }, + }) + .then((resp) => { + if (expectedStatusCode) { + expect(resp.status).to.eq(expectedStatusCode); + } - return cy.wrap(interceptedUrls); + return resp; + }); }); -Cypress.Commands.add('iFrame', () => { - return cy - .get('[data-testid="ember-iframe"]', { log: false }) - .its('0.contentDocument.body', { log: false }) - .should('not.be.empty') - .then((body) => cy.wrap(body)); +/** + * set a v3 / v1 resource + */ +Cypress.Commands.add('setRancherResource', (prefix, resourceType, resourceId, body) => { + return cy.request({ + method: 'PUT', + url: `${ Cypress.env('api') }/${ prefix }/${ resourceType }/${ resourceId }`, + headers: { + 'x-api-csrf': token.value, + Accept: 'application/json' + }, + body + }) + .then((resp) => { + expect(resp.status).to.eq(200); + }); }); diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts index bef88307252..71a94e659f4 100644 --- a/cypress/support/e2e.ts +++ b/cypress/support/e2e.ts @@ -1,5 +1,6 @@ import '@cypress/code-coverage/support'; -import './commands'; +import './commands/commands'; +import './commands/rancher-api-commands.ts'; import registerCypressGrep from '@cypress/grep/src/support'; registerCypressGrep();