From deb68e5511a6b23438689b6cd6963d806c0e52f8 Mon Sep 17 00:00:00 2001 From: Subodh Singh Date: Wed, 4 Sep 2024 13:14:58 +0530 Subject: [PATCH 1/3] test: [M3-6615, M3-8507] - Cypress test for empty Linode landing page and restricted user Linode landing page --- .../smoke-linode-landing-table.spec.ts | 124 +++++++++++++++++- 1 file changed, 123 insertions(+), 1 deletion(-) diff --git a/packages/manager/cypress/e2e/core/linodes/smoke-linode-landing-table.spec.ts b/packages/manager/cypress/e2e/core/linodes/smoke-linode-landing-table.spec.ts index f25d7ac4ef1..6f2b82dfa93 100644 --- a/packages/manager/cypress/e2e/core/linodes/smoke-linode-landing-table.spec.ts +++ b/packages/manager/cypress/e2e/core/linodes/smoke-linode-landing-table.spec.ts @@ -15,11 +15,17 @@ import { apiMatcher } from 'support/util/intercepts'; import { chooseRegion, getRegionById } from 'support/util/regions'; import { authenticate } from 'support/api/authentication'; import { mockGetLinodes } from 'support/intercepts/linodes'; -import { userPreferencesFactory } from '@src/factories'; +import { userPreferencesFactory, profileFactory } from '@src/factories'; +import { accountUserFactory } from '@src/factories/accountUsers'; +import { grantsFactory } from '@src/factories/grants'; +import { mockGetUser } from 'support/intercepts/account'; import { mockGetUserPreferences, mockUpdateUserPreferences, + mockGetProfile, + mockGetProfileGrants, } from 'support/intercepts/profile'; +import { randomLabel } from 'support/util/random'; const mockLinodes = new Array(5).fill(null).map( (_item: null, index: number): Linode => { @@ -33,6 +39,10 @@ const mockLinodes = new Array(5).fill(null).map( const mockLinodesData = makeResourcePage(mockLinodes); +const emptyLinode: Linode[] = []; + +const emptyLinodeData = makeResourcePage(emptyLinode); + const sortByRegion = (a: Linode, b: Linode) => { return a.region.localeCompare(b.region); }; @@ -386,3 +396,115 @@ describe('linode landing checks', () => { cy.findByText('Created:').should('not.exist'); }); }); + +describe('linode landing checks for empty state', () => { + beforeEach(() => { + const mockAccountSettings = accountSettingsFactory.build({ + managed: false, + }); + + cy.intercept('GET', apiMatcher('account/settings'), (req) => { + req.reply(mockAccountSettings); + }).as('getAccountSettings'); + cy.intercept('GET', apiMatcher('profile')).as('getProfile'); + cy.intercept('GET', apiMatcher('linode/instances/*'), (req) => { + req.reply(emptyLinodeData); + }); + cy.visitWithLogin('/', { preferenceOverrides }); + cy.wait('@getAccountSettings'); + cy.url().should('endWith', routes.linodeLanding); + }); + + it('checks empty state on linode landing page', () => { + cy.get('div[data-qa-placeholder-container="resources-section"]').as( + 'resourcesSection' + ); + cy.get('@resourcesSection') + .get('h1[data-qa-header]') + .contains('Linodes') + .as('linodesHeader'); + + // Assert that fields with Linodes and Cloud-based virtual machines text are visible + cy.get('@linodesHeader').should('be.visible'); + cy.get('@linodesHeader') + .next('h2') + .should('be.visible') + .should('have.text', 'Cloud-based virtual machines'); + + //Assert that recommended section is visible - Getting Started Guides, Deploy an App and Video Playlist + cy.get('@resourcesSection') + .contains('h2', 'Getting Started Guides') + .should('be.visible'); + cy.get('@resourcesSection') + .contains('h2', 'Deploy an App') + .should('be.visible'); + cy.get('@resourcesSection') + .contains('h2', 'Video Playlist') + .should('be.visible'); + + // Assert that Create Linode button is visible and enabled + ui.button + .findByTitle('Create Linode') + .should('be.visible') + .and('be.enabled'); + + // Assert that List of Liondes table does not exist + cy.get('table[aria-label="List of Linodes"]').should('not.exist'); + + // Assert that Docs link does not exist + cy.get( + 'a[aria-label="Docs - link opens in a new tab"][data-testid="external-link"]' + ).should('not.exist'); + + // Assert that Download CSV button does not exist + cy.get('span[data-testid="loadingIcon"]') + .contains('Download CSV') + .should('not.exist'); + }); +}); + +describe('linode landing checks for restricted user', () => { + beforeEach(() => { + const mockProfile = profileFactory.build({ + username: randomLabel(), + restricted: true, + }); + + const mockUser = accountUserFactory.build({ + username: mockProfile.username, + restricted: true, + user_type: 'default', + }); + + const mockGrants = grantsFactory.build({ + global: { + add_linodes: false, + }, + }); + + mockGetProfile(mockProfile); + mockGetProfileGrants(mockGrants); + mockGetUser(mockUser); + cy.intercept('GET', apiMatcher('linode/instances/*'), (req) => { + req.reply(emptyLinodeData); + }); + cy.visitWithLogin('/', { preferenceOverrides }); + cy.url().should('endWith', routes.linodeLanding); + }); + + it('checks restricted user has no access to create linode on linode landing page', () => { + // Assert that Create Linode button is visible and disabled + ui.button + .findByTitle('Create Linode') + .should('be.visible') + .and('be.disabled') + .trigger('mouseover'); + + // Assert that tooltip is visible with message + ui.tooltip + .findByText( + "You don't have permissions to create Linodes. Please contact your account administrator to request the necessary permissions." + ) + .should('be.visible'); + }); +}); From c838baec6ebc6121139ed671ac55c5e5141f39c0 Mon Sep 17 00:00:00 2001 From: Subodh Singh Date: Wed, 4 Sep 2024 13:40:59 +0530 Subject: [PATCH 2/3] Added changeset: Cypress test for empty Linode landing page and restricted user Linode landing page --- packages/manager/.changeset/pr-10882-tests-1725437459486.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 packages/manager/.changeset/pr-10882-tests-1725437459486.md diff --git a/packages/manager/.changeset/pr-10882-tests-1725437459486.md b/packages/manager/.changeset/pr-10882-tests-1725437459486.md new file mode 100644 index 00000000000..0d5989dcb4b --- /dev/null +++ b/packages/manager/.changeset/pr-10882-tests-1725437459486.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Tests +--- + +Cypress test for empty Linode landing page and restricted user Linode landing page ([#10882](https://github.com/linode/manager/pull/10882)) From dbc04a5811cc5c60a8e16a7c8c058708ec04025f Mon Sep 17 00:00:00 2001 From: Subodh Singh Date: Thu, 5 Sep 2024 14:46:13 +0530 Subject: [PATCH 3/3] Worked on review comments for refactoring --- .../smoke-linode-landing-table.spec.ts | 42 +++++++------------ 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/packages/manager/cypress/e2e/core/linodes/smoke-linode-landing-table.spec.ts b/packages/manager/cypress/e2e/core/linodes/smoke-linode-landing-table.spec.ts index 6f2b82dfa93..d654d58ea32 100644 --- a/packages/manager/cypress/e2e/core/linodes/smoke-linode-landing-table.spec.ts +++ b/packages/manager/cypress/e2e/core/linodes/smoke-linode-landing-table.spec.ts @@ -39,10 +39,6 @@ const mockLinodes = new Array(5).fill(null).map( const mockLinodesData = makeResourcePage(mockLinodes); -const emptyLinode: Linode[] = []; - -const emptyLinodeData = makeResourcePage(emptyLinode); - const sortByRegion = (a: Linode, b: Linode) => { return a.region.localeCompare(b.region); }; @@ -399,23 +395,17 @@ describe('linode landing checks', () => { describe('linode landing checks for empty state', () => { beforeEach(() => { - const mockAccountSettings = accountSettingsFactory.build({ - managed: false, - }); - - cy.intercept('GET', apiMatcher('account/settings'), (req) => { - req.reply(mockAccountSettings); - }).as('getAccountSettings'); - cy.intercept('GET', apiMatcher('profile')).as('getProfile'); - cy.intercept('GET', apiMatcher('linode/instances/*'), (req) => { - req.reply(emptyLinodeData); - }); - cy.visitWithLogin('/', { preferenceOverrides }); - cy.wait('@getAccountSettings'); - cy.url().should('endWith', routes.linodeLanding); + // Mock setup to display the Linode landing page in an empty state + mockGetLinodes([]).as('getLinodes'); }); it('checks empty state on linode landing page', () => { + // Login and wait for application to load + cy.visitWithLogin(routes.linodeLanding); + cy.wait('@getLinodes'); + cy.url().should('endWith', routes.linodeLanding); + + // Aliases created for accessing child elements during assertions cy.get('div[data-qa-placeholder-container="resources-section"]').as( 'resourcesSection' ); @@ -461,10 +451,10 @@ describe('linode landing checks for empty state', () => { .contains('Download CSV') .should('not.exist'); }); -}); -describe('linode landing checks for restricted user', () => { - beforeEach(() => { + it('checks restricted user has no access to create linode on linode landing page', () => { + // Mock setup for user profile, account user, and user grants with restricted permissions, + // simulating a default user without the ability to add Linodes. const mockProfile = profileFactory.build({ username: randomLabel(), restricted: true, @@ -485,14 +475,12 @@ describe('linode landing checks for restricted user', () => { mockGetProfile(mockProfile); mockGetProfileGrants(mockGrants); mockGetUser(mockUser); - cy.intercept('GET', apiMatcher('linode/instances/*'), (req) => { - req.reply(emptyLinodeData); - }); - cy.visitWithLogin('/', { preferenceOverrides }); + + // Login and wait for application to load + cy.visitWithLogin(routes.linodeLanding); + cy.wait('@getLinodes'); cy.url().should('endWith', routes.linodeLanding); - }); - it('checks restricted user has no access to create linode on linode landing page', () => { // Assert that Create Linode button is visible and disabled ui.button .findByTitle('Create Linode')