diff --git a/packages/manager/.changeset/pr-10889-tests-1725485099504.md b/packages/manager/.changeset/pr-10889-tests-1725485099504.md new file mode 100644 index 00000000000..0145a26624d --- /dev/null +++ b/packages/manager/.changeset/pr-10889-tests-1725485099504.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Tests +--- + +Update remaining Linode Create Cypress tests run against Linode Create v2 ([#10889](https://github.com/linode/manager/pull/10889)) diff --git a/packages/manager/cypress/e2e/core/general/gdpr-agreement.spec.ts b/packages/manager/cypress/e2e/core/general/gdpr-agreement.spec.ts index 089e766fb93..9141cae6b50 100644 --- a/packages/manager/cypress/e2e/core/general/gdpr-agreement.spec.ts +++ b/packages/manager/cypress/e2e/core/general/gdpr-agreement.spec.ts @@ -1,16 +1,11 @@ import { ui } from 'support/ui'; -import { fbtClick, getClick } from 'support/helpers'; -import { regionFactory } from '@src/factories'; +import { linodeFactory, regionFactory } from '@src/factories'; import { randomString, randomLabel } from 'support/util/random'; import { mockGetRegions } from 'support/intercepts/regions'; import { mockGetAccountAgreements } from 'support/intercepts/account'; -import { - mockAppendFeatureFlags, - mockGetFeatureFlagClientstream, -} from 'support/intercepts/feature-flags'; -import { makeFeatureFlagData } from 'support/util/feature-flags'; import type { Region } from '@linode/api-v4'; +import { mockCreateLinode } from 'support/intercepts/linodes'; const mockRegions: Region[] = [ regionFactory.build({ @@ -102,15 +97,7 @@ describe('GDPR agreement', () => { cy.get('[data-testid="eu-agreement-checkbox"]').should('not.exist'); }); - it('needs the agreement checked to validate the form', () => { - // This test does not apply to Linode Create v2 because - // Linode Create v2 allows you to press "Create Linode" - // without checking the GDPR checkbox. (The user will - // get a validation error if they have not agreed). - mockAppendFeatureFlags({ - linodeCreateRefactor: makeFeatureFlagData(false), - }); - mockGetFeatureFlagClientstream(); + it('needs the agreement checked to submit the form', () => { mockGetRegions(mockRegions).as('getRegions'); mockGetAccountAgreements({ privacy_policy: false, @@ -120,26 +107,50 @@ describe('GDPR agreement', () => { const linodeLabel = randomLabel(); cy.visitWithLogin('/linodes/create'); - cy.wait(['@getAgreements', '@getRegions']); + cy.wait(['@getRegions']); // Paris should have the agreement ui.regionSelect.find().click(); ui.regionSelect.findItemByRegionId('fr-par').click(); - cy.get('[data-testid="eu-agreement-checkbox"]').should('be.visible'); - // Fill out the form - fbtClick('Shared CPU'); - getClick('[id="g6-nanode-1"]'); - getClick('#linode-label').clear().type(linodeLabel); - cy.get('#root-password').type(rootpass); + cy.wait('@getAgreements'); + + cy.findByText('Shared CPU').click(); + + cy.get('[id="g6-nanode-1"]').click(); + + cy.findByLabelText('Linode Label').clear().type(linodeLabel); + + cy.findByLabelText('Root Password').type(rootpass); - // expect the button to be disabled - cy.get('[data-qa-deploy-linode="true"]').should('be.disabled'); + cy.get('[data-testid="eu-agreement-checkbox"]') + .scrollIntoView() + .should('be.visible'); + + cy.findByText('Create Linode') + .scrollIntoView() + .should('be.enabled') + .should('be.visible') + .click(); + + cy.findByText( + 'You must agree to the EU agreement to deploy to this region.' + ).should('be.visible'); // check the agreement - getClick('#gdpr-checkbox'); + cy.get('#gdpr-checkbox').click(); + + cy.findByText( + 'You must agree to the EU agreement to deploy to this region.' + ).should('not.exist'); + + mockCreateLinode(linodeFactory.build()).as('createLinode'); + + cy.findByText('Create Linode') + .should('be.enabled') + .should('be.visible') + .click(); - // expect the button to be enabled - cy.get('[data-qa-deploy-linode="true"]').should('not.be.disabled'); + cy.wait('@createLinode'); }); }); diff --git a/packages/manager/cypress/e2e/core/linodes/create-linode-mobile.spec.ts b/packages/manager/cypress/e2e/core/linodes/create-linode-mobile.spec.ts index bf7774cc0bd..1cc4bfa5f59 100644 --- a/packages/manager/cypress/e2e/core/linodes/create-linode-mobile.spec.ts +++ b/packages/manager/cypress/e2e/core/linodes/create-linode-mobile.spec.ts @@ -7,23 +7,10 @@ import { MOBILE_VIEWPORTS } from 'support/constants/environment'; import { linodeCreatePage } from 'support/ui/pages'; import { randomLabel, randomNumber, randomString } from 'support/util/random'; import { chooseRegion } from 'support/util/regions'; -import { - mockAppendFeatureFlags, - mockGetFeatureFlagClientstream, -} from 'support/intercepts/feature-flags'; -import { makeFeatureFlagData } from 'support/util/feature-flags'; import { ui } from 'support/ui'; import { mockCreateLinode } from 'support/intercepts/linodes'; describe('Linode create mobile smoke', () => { - // TODO Remove feature flag mocks when `linodeCreateRefactor` flag is retired. - beforeEach(() => { - mockAppendFeatureFlags({ - linodeCreateRefactor: makeFeatureFlagData(true), - }); - mockGetFeatureFlagClientstream(); - }); - MOBILE_VIEWPORTS.forEach((viewport) => { /* * - Confirms Linode create flow can be completed on common mobile screen sizes diff --git a/packages/manager/cypress/e2e/core/linodes/create-linode-region-select.spec.ts b/packages/manager/cypress/e2e/core/linodes/create-linode-region-select.spec.ts new file mode 100644 index 00000000000..707f57f0b25 --- /dev/null +++ b/packages/manager/cypress/e2e/core/linodes/create-linode-region-select.spec.ts @@ -0,0 +1,96 @@ +import { ui } from 'support/ui'; +import { + regionFactory, +} from '@src/factories'; +import { mockGetRegions } from 'support/intercepts/regions'; +import { extendRegion } from 'support/util/regions'; + +import type { ExtendedRegion } from 'support/util/regions'; + +const mockRegions: ExtendedRegion[] = [ + extendRegion( + regionFactory.build({ + capabilities: ['Linodes'], + country: 'uk', + id: 'eu-west', + label: 'London, UK', + }) + ), + extendRegion( + regionFactory.build({ + capabilities: ['Linodes'], + country: 'sg', + id: 'ap-south', + label: 'Singapore, SG', + }) + ), + extendRegion( + regionFactory.build({ + capabilities: ['Linodes'], + id: 'us-east', + label: 'Newark, NJ', + }) + ), + extendRegion( + regionFactory.build({ + capabilities: ['Linodes'], + id: 'us-central', + label: 'Dallas, TX', + }) + ), +]; + +describe('Linode Create Region Select', () => { + /* + * Region select test. + * + * TODO: Cypress + * Move this to cypress component testing once the setup is complete - see https://github.com/linode/manager/pull/10134 + * + * - Confirms that region select dropdown is visible and interactive. + * - Confirms that region select dropdown is populated with expected regions. + * - Confirms that region select dropdown is sorted alphabetically by region, with North America first. + * - Confirms that region select dropdown is populated with expected DCs, sorted alphabetically. + */ + it('region select', () => { + mockGetRegions(mockRegions).as('getRegions'); + + cy.visitWithLogin('linodes/create'); + + cy.wait('@getRegions'); + + // Confirm that region select dropdown is visible and interactive. + ui.regionSelect.find().click(); + cy.get('[data-qa-autocomplete-popper="true"]').should('be.visible'); + + // Confirm that region select dropdown are grouped by region, + // sorted alphabetically, with North America first. + cy.get('.MuiAutocomplete-groupLabel') + .should('have.length', 3) + .should((group) => { + expect(group[0]).to.contain('North America'); + expect(group[1]).to.contain('Asia'); + expect(group[2]).to.contain('Europe'); + }); + + // Confirm that region select dropdown is populated with expected regions, sorted alphabetically. + cy.get('[data-qa-option]').should('exist').should('have.length', 4); + mockRegions.forEach((region) => { + cy.get('[data-qa-option]').contains(region.label); + }); + + // Select an option + cy.findByTestId('eu-west').click(); + // Confirm the popper is closed + cy.get('[data-qa-autocomplete-popper="true"]').should('not.exist'); + + // Confirm that the selected region is displayed in the input field. + cy.findByLabelText('Region').should( + 'have.value', + 'UK, London (eu-west)' + ); + + // Confirm that selecting a valid region updates the Plan Selection panel. + expect(cy.get('[data-testid="table-row-empty"]').should('not.exist')); + }); +}); \ No newline at end of file diff --git a/packages/manager/cypress/e2e/core/linodes/create-linode-view-code-snippet.spec.ts b/packages/manager/cypress/e2e/core/linodes/create-linode-view-code-snippet.spec.ts index d801c3046b7..5dda8a18cb6 100644 --- a/packages/manager/cypress/e2e/core/linodes/create-linode-view-code-snippet.spec.ts +++ b/packages/manager/cypress/e2e/core/linodes/create-linode-view-code-snippet.spec.ts @@ -12,6 +12,7 @@ import { } from 'support/intercepts/feature-flags'; import { makeFeatureFlagData } from 'support/util/feature-flags'; +import { chooseRegion } from 'support/util/regions'; describe('Create Linode', () => { /* @@ -23,7 +24,6 @@ describe('Create Linode', () => { beforeEach(() => { mockAppendFeatureFlags({ apicliDxToolsAdditions: makeFeatureFlagData(true), - linodeCreateRefactor: makeFeatureFlagData(true), }); mockGetFeatureFlagClientstream(); }); @@ -149,13 +149,13 @@ describe('Create Linode', () => { }); }); }); + describe('Create Linode flow with apicliDxToolsAdditions disabled', () => { // Enable the `apicliDxToolsAdditions` feature flag. // TODO Delete these mocks and test once `apicliDxToolsAdditions` feature flag is retired. beforeEach(() => { mockAppendFeatureFlags({ apicliDxToolsAdditions: makeFeatureFlagData(false), - linodeCreateRefactor: makeFeatureFlagData(true), }); mockGetFeatureFlagClientstream(); }); @@ -203,4 +203,75 @@ describe('Create Linode', () => { }); }); }); + + it('creates a linode via CLI', () => { + const linodeLabel = randomLabel(); + const linodePass = randomString(32); + const linodeRegion = chooseRegion(); + + cy.visitWithLogin('/linodes/create'); + + ui.regionSelect.find().click(); + ui.autocompletePopper + .findByTitle(`${linodeRegion.label} (${linodeRegion.id})`) + .should('exist') + .click(); + + cy.get('[id="g6-dedicated-2"]').click(); + + cy.findByLabelText('Linode Label') + .should('have.value', `debian-${linodeRegion.id}`); + + cy.findByLabelText('Linode Label') + .should('be.visible') + .should('be.enabled') + .clear() + .type(linodeLabel); + + cy.findByLabelText('Root Password') + .should('be.visible') + .should('be.enabled') + .type(linodePass); + + ui.button + .findByTitle('Create using command line') + .should('be.visible') + .should('be.enabled') + .click(); + + ui.dialog + .findByTitle('Create Linode') + .should('be.visible') + .within(() => { + // Switch to cURL view if necessary. + cy.findByText('cURL') + .should('be.visible') + .click(); + + // Confirm that cURL command has expected details. + [ + `"region": "${linodeRegion.id}"`, + `"type": "g6-dedicated-2"`, + `"label": "${linodeLabel}"`, + `"root_pass": "${linodePass}"`, + ].forEach((line: string) => + cy.findByText(line, { exact: false }).should('be.visible') + ); + + cy.findByText('Linode CLI').should('be.visible').click(); + + [ + `--region ${linodeRegion.id}`, + '--type g6-dedicated-2', + `--label ${linodeLabel}`, + `--root_pass ${linodePass}`, + ].forEach((line: string) => cy.contains(line).should('be.visible')); + + ui.buttonGroup + .findButtonByTitle('Close') + .should('be.visible') + .should('be.enabled') + .click(); + }); + }); }); diff --git a/packages/manager/cypress/e2e/core/linodes/create-linode-with-add-ons.spec.ts b/packages/manager/cypress/e2e/core/linodes/create-linode-with-add-ons.spec.ts index 23d62bf666f..c6d8befe082 100644 --- a/packages/manager/cypress/e2e/core/linodes/create-linode-with-add-ons.spec.ts +++ b/packages/manager/cypress/e2e/core/linodes/create-linode-with-add-ons.spec.ts @@ -1,27 +1,14 @@ import { linodeFactory } from 'src/factories'; -import { - mockAppendFeatureFlags, - mockGetFeatureFlagClientstream, -} from 'support/intercepts/feature-flags'; import { mockCreateLinode, mockGetLinodeDetails, } from 'support/intercepts/linodes'; import { ui } from 'support/ui'; import { linodeCreatePage } from 'support/ui/pages'; -import { makeFeatureFlagData } from 'support/util/feature-flags'; import { randomLabel, randomNumber, randomString } from 'support/util/random'; import { chooseRegion } from 'support/util/regions'; describe('Create Linode with Add-ons', () => { - // TODO Remove feature flag mocks when `linodeCreateRefactor` flag is retired. - beforeEach(() => { - mockAppendFeatureFlags({ - linodeCreateRefactor: makeFeatureFlagData(true), - }); - mockGetFeatureFlagClientstream(); - }); - /* * - Confirms UI flow to create a Linode with backups using mock API data. * - Confirms that backups is reflected in create summary section. diff --git a/packages/manager/cypress/e2e/core/linodes/create-linode-with-dc-specific-pricing.spec.ts b/packages/manager/cypress/e2e/core/linodes/create-linode-with-dc-specific-pricing.spec.ts new file mode 100644 index 00000000000..a6442d4f15c --- /dev/null +++ b/packages/manager/cypress/e2e/core/linodes/create-linode-with-dc-specific-pricing.spec.ts @@ -0,0 +1,122 @@ +import { ui } from 'support/ui'; +import { randomLabel } from 'support/util/random'; +import { getRegionById } from 'support/util/regions'; +import { + linodeFactory, +} from '@src/factories'; +import { + dcPricingPlanPlaceholder, + dcPricingMockLinodeTypes, + dcPricingDocsLabel, + dcPricingDocsUrl, +} from 'support/constants/dc-specific-pricing'; +import { + mockCreateLinode, + mockGetLinodeType, + mockGetLinodeTypes, +} from 'support/intercepts/linodes'; + +describe('Create Linode with DC-specific pricing', () => { + /* + * - Confirms DC-specific pricing UI flow works as expected during Linode creation. + * - Confirms that pricing docs link is shown in "Region" section. + * - Confirms that backups pricing is correct when selecting a region with a different price structure. + */ + it('shows DC-specific pricing information during create flow', () => { + const linodeLabel = randomLabel(); + const initialRegion = getRegionById('us-west'); + const newRegion = getRegionById('us-east'); + + const mockLinode = linodeFactory.build({ + label: linodeLabel, + region: initialRegion.id, + type: dcPricingMockLinodeTypes[0].id, + }); + + const currentPrice = dcPricingMockLinodeTypes[0].region_prices.find( + (regionPrice) => regionPrice.id === initialRegion.id + )!; + const currentBackupPrice = dcPricingMockLinodeTypes[0].addons.backups.region_prices.find( + (regionPrice) => regionPrice.id === initialRegion.id + )!; + const newPrice = dcPricingMockLinodeTypes[1].region_prices.find( + (linodeType) => linodeType.id === newRegion.id + )!; + const newBackupPrice = dcPricingMockLinodeTypes[1].addons.backups.region_prices.find( + (regionPrice) => regionPrice.id === newRegion.id + )!; + + // Mock requests to get individual types. + mockGetLinodeType(dcPricingMockLinodeTypes[0]); + mockGetLinodeType(dcPricingMockLinodeTypes[1]); + mockGetLinodeTypes(dcPricingMockLinodeTypes).as('getLinodeTypes'); + + // intercept request + cy.visitWithLogin('/linodes/create'); + cy.wait(['@getLinodeTypes']); + + mockCreateLinode(mockLinode).as('linodeCreated'); + + cy.get('[data-qa-header="Create"]').should('have.text', 'Create'); + + ui.button.findByTitle("Create Linode").click(); + + // A message is shown to instruct users to select a region in order to view plans and prices + cy.get('[data-qa-tp="Linode Plan"]').should( + 'contain.text', + 'Plan is required.' + ); + cy.get('[data-qa-tp="Linode Plan"]').should( + 'contain.text', + dcPricingPlanPlaceholder + ); + + // Check the 'Backups' add on + cy.get('[data-testid="backups"]').should('be.visible').click(); + ui.regionSelect.find().click(); + ui.regionSelect.findItemByRegionLabel(initialRegion.label).click(); + cy.findByText('Shared CPU').click(); + cy.get(`[id="${dcPricingMockLinodeTypes[0].id}"]`).click(); + // Confirm that the backup prices are displayed as expected. + cy.get('[data-qa-add-ons="true"]') + .within(() => { + cy.findByText(`$${currentBackupPrice.monthly}`).should('be.visible'); + cy.findByText('per month').should('be.visible'); + }); + // Confirm that the checkout summary at the bottom of the page reflects the correct price. + cy.get('[data-qa-linode-create-summary="true"]').within(() => { + cy.findByText(`$${currentPrice.monthly!.toFixed(2)}/month`).should( + 'be.visible' + ); + cy.findByText('Backups').should('be.visible'); + cy.findByText(`$${currentBackupPrice.monthly!.toFixed(2)}/month`).should( + 'be.visible' + ); + }); + + // Confirm there is a docs link to the pricing page. + cy.findByText(dcPricingDocsLabel) + .should('be.visible') + .should('have.attr', 'href', dcPricingDocsUrl); + + ui.regionSelect.find().click().type(`${newRegion.label} {enter}`); + cy.findByText('Shared CPU').click(); + cy.get(`[id="${dcPricingMockLinodeTypes[0].id}"]`).click(); + // Confirm that the backup prices are displayed as expected. + cy.get('[data-qa-add-ons="true"]') + .within(() => { + cy.findByText(`$${newBackupPrice.monthly}`).should('be.visible'); + cy.findByText('per month').should('be.visible'); + }); + // Confirms that the summary updates to reflect price changes if the user changes their region and plan selection. + cy.get('[data-qa-linode-create-summary="true"]').within(() => { + cy.findByText(`$${newPrice.monthly!.toFixed(2)}/month`).should( + 'be.visible' + ); + cy.findByText('Backups').should('be.visible'); + cy.findByText(`$${newBackupPrice.monthly!.toFixed(2)}/month`).should( + 'be.visible' + ); + }); + }); +}); \ No newline at end of file diff --git a/packages/manager/cypress/e2e/core/linodes/create-linode-with-disk-encryption.spec.ts b/packages/manager/cypress/e2e/core/linodes/create-linode-with-disk-encryption.spec.ts new file mode 100644 index 00000000000..5c69ada4f61 --- /dev/null +++ b/packages/manager/cypress/e2e/core/linodes/create-linode-with-disk-encryption.spec.ts @@ -0,0 +1,85 @@ +import { ui } from 'support/ui'; +import { + accountFactory, + regionFactory, +} from '@src/factories'; +import { mockGetRegions } from 'support/intercepts/regions'; +import { mockGetAccount } from 'support/intercepts/account'; +import { + mockAppendFeatureFlags, +} from 'support/intercepts/feature-flags'; +import { makeFeatureFlagData } from 'support/util/feature-flags'; +import { + checkboxTestId, + headerTestId, +} from 'src/components/Encryption/Encryption'; + +describe('Create Linode with Disk Encryption', () => { + it('should not have a "Disk Encryption" section visible if the feature flag is off and user does not have capability', () => { + // Mock feature flag -- @TODO LDE: Remove feature flag once LDE is fully rolled out + mockAppendFeatureFlags({ + linodeDiskEncryption: makeFeatureFlagData(false), + }).as('getFeatureFlags'); + + // Mock account response + const mockAccount = accountFactory.build({ + capabilities: ['Linodes'], + }); + + mockGetAccount(mockAccount).as('getAccount'); + + // intercept request + cy.visitWithLogin('/linodes/create'); + cy.wait(['@getFeatureFlags', '@getAccount']); + + // Check if section is visible + cy.get(`[data-testid=${headerTestId}]`).should('not.exist'); + }); + + it('should have a "Disk Encryption" section visible if feature flag is on and user has the capability', () => { + // Mock feature flag -- @TODO LDE: Remove feature flag once LDE is fully rolled out + mockAppendFeatureFlags({ + linodeDiskEncryption: makeFeatureFlagData(true), + }).as('getFeatureFlags'); + + // Mock account response + const mockAccount = accountFactory.build({ + capabilities: ['Linodes', 'Disk Encryption'], + }); + + const mockRegion = regionFactory.build({ + capabilities: ['Linodes', 'Disk Encryption'], + }); + + const mockRegionWithoutDiskEncryption = regionFactory.build({ + capabilities: ['Linodes'], + }); + + const mockRegions = [mockRegion, mockRegionWithoutDiskEncryption]; + + mockGetAccount(mockAccount).as('getAccount'); + mockGetRegions(mockRegions); + + // intercept request + cy.visitWithLogin('/linodes/create'); + cy.wait(['@getFeatureFlags', '@getAccount']); + + // Check if section is visible + cy.get(`[data-testid="${headerTestId}"]`).should('exist'); + + // "Encrypt Disk" checkbox should be disabled if a region that does not support LDE is selected + ui.regionSelect.find().click(); + ui.select + .findItemByText( + `${mockRegionWithoutDiskEncryption.label} (${mockRegionWithoutDiskEncryption.id})` + ) + .click(); + + cy.get(`[data-testid="${checkboxTestId}"]`).should('be.disabled'); + + ui.regionSelect.find().click(); + ui.select.findItemByText(`${mockRegion.label} (${mockRegion.id})`).click(); + + cy.get(`[data-testid="${checkboxTestId}"]`).should('be.enabled'); + }); +}); \ No newline at end of file diff --git a/packages/manager/cypress/e2e/core/linodes/create-linode-with-firewall.spec.ts b/packages/manager/cypress/e2e/core/linodes/create-linode-with-firewall.spec.ts index 1659a07189c..70a759c140a 100644 --- a/packages/manager/cypress/e2e/core/linodes/create-linode-with-firewall.spec.ts +++ b/packages/manager/cypress/e2e/core/linodes/create-linode-with-firewall.spec.ts @@ -3,10 +3,6 @@ import { firewallFactory, firewallTemplateFactory, } from 'src/factories'; -import { - mockAppendFeatureFlags, - mockGetFeatureFlagClientstream, -} from 'support/intercepts/feature-flags'; import { mockCreateLinode, mockGetLinodeDetails, @@ -19,19 +15,10 @@ import { } from 'support/intercepts/firewalls'; import { ui } from 'support/ui'; import { linodeCreatePage } from 'support/ui/pages'; -import { makeFeatureFlagData } from 'support/util/feature-flags'; import { randomLabel, randomNumber, randomString } from 'support/util/random'; import { chooseRegion } from 'support/util/regions'; describe('Create Linode with Firewall', () => { - // TODO Remove feature flag mocks when `linodeCreateRefactor` flag is retired. - beforeEach(() => { - mockAppendFeatureFlags({ - linodeCreateRefactor: makeFeatureFlagData(true), - }); - mockGetFeatureFlagClientstream(); - }); - /* * - Confirms UI flow to create a Linode with an existing Firewall using mock API data. * - Confirms that Firewall is reflected in create summary section. diff --git a/packages/manager/cypress/e2e/core/linodes/create-linode-with-ssh-key.spec.ts b/packages/manager/cypress/e2e/core/linodes/create-linode-with-ssh-key.spec.ts index 07a04310671..b613f8cf384 100644 --- a/packages/manager/cypress/e2e/core/linodes/create-linode-with-ssh-key.spec.ts +++ b/packages/manager/cypress/e2e/core/linodes/create-linode-with-ssh-key.spec.ts @@ -3,11 +3,6 @@ import { linodeFactory, sshKeyFactory, } from 'src/factories'; -import { - mockAppendFeatureFlags, - mockGetFeatureFlagClientstream, -} from 'support/intercepts/feature-flags'; -import { makeFeatureFlagData } from 'support/util/feature-flags'; import { randomLabel, randomNumber, randomString } from 'support/util/random'; import { chooseRegion } from 'support/util/regions'; import { mockGetUser, mockGetUsers } from 'support/intercepts/account'; @@ -17,14 +12,6 @@ import { ui } from 'support/ui'; import { mockCreateSSHKey } from 'support/intercepts/profile'; describe('Create Linode with SSH Key', () => { - // TODO Remove feature flag mocks when `linodeCreateRefactor` flag is retired. - beforeEach(() => { - mockAppendFeatureFlags({ - linodeCreateRefactor: makeFeatureFlagData(true), - }); - mockGetFeatureFlagClientstream(); - }); - /* * - Confirms UI flow when creating a Linode with an authorized SSH key. * - Confirms that existing SSH keys are listed on page and can be selected. diff --git a/packages/manager/cypress/e2e/core/linodes/create-linode-with-user-data.spec.ts b/packages/manager/cypress/e2e/core/linodes/create-linode-with-user-data.spec.ts index 21096becdf3..4d3be85fd49 100644 --- a/packages/manager/cypress/e2e/core/linodes/create-linode-with-user-data.spec.ts +++ b/packages/manager/cypress/e2e/core/linodes/create-linode-with-user-data.spec.ts @@ -1,8 +1,4 @@ import { imageFactory, linodeFactory, regionFactory } from 'src/factories'; -import { - mockAppendFeatureFlags, - mockGetFeatureFlagClientstream, -} from 'support/intercepts/feature-flags'; import { mockGetAllImages, mockGetImage } from 'support/intercepts/images'; import { mockCreateLinode, @@ -11,18 +7,10 @@ import { import { mockGetRegions } from 'support/intercepts/regions'; import { ui } from 'support/ui'; import { linodeCreatePage } from 'support/ui/pages'; -import { makeFeatureFlagData } from 'support/util/feature-flags'; import { randomLabel, randomNumber, randomString } from 'support/util/random'; import { chooseRegion } from 'support/util/regions'; describe('Create Linode with user data', () => { - beforeEach(() => { - mockAppendFeatureFlags({ - linodeCreateRefactor: makeFeatureFlagData(true), - }); - mockGetFeatureFlagClientstream(); - }); - /* * - Confirms UI flow to create a Linode with cloud-init user data specified. * - Confirms that outgoing API request contains expected user data payload. diff --git a/packages/manager/cypress/e2e/core/linodes/create-linode-with-vlan.spec.ts b/packages/manager/cypress/e2e/core/linodes/create-linode-with-vlan.spec.ts index 65361c25d01..d80d2a963b9 100644 --- a/packages/manager/cypress/e2e/core/linodes/create-linode-with-vlan.spec.ts +++ b/packages/manager/cypress/e2e/core/linodes/create-linode-with-vlan.spec.ts @@ -2,11 +2,6 @@ import { linodeFactory, regionFactory, VLANFactory } from 'src/factories'; import { mockGetRegions } from 'support/intercepts/regions'; import { ui } from 'support/ui'; import { linodeCreatePage } from 'support/ui/pages'; -import { - mockAppendFeatureFlags, - mockGetFeatureFlagClientstream, -} from 'support/intercepts/feature-flags'; -import { makeFeatureFlagData } from 'support/util/feature-flags'; import { chooseRegion } from 'support/util/regions'; import { randomIp, @@ -18,14 +13,6 @@ import { mockGetVLANs } from 'support/intercepts/vlans'; import { mockCreateLinode } from 'support/intercepts/linodes'; describe('Create Linode with VLANs', () => { - // TODO Remove feature flag mocks when `linodeCreateRefactor` flag is retired. - beforeEach(() => { - mockAppendFeatureFlags({ - linodeCreateRefactor: makeFeatureFlagData(true), - }); - mockGetFeatureFlagClientstream(); - }); - /* * - Uses mock API data to confirm VLAN attachment UI flow during Linode create. * - Confirms that outgoing Linode create API request contains expected data for VLAN. diff --git a/packages/manager/cypress/e2e/core/linodes/create-linode-with-vpc.spec.ts b/packages/manager/cypress/e2e/core/linodes/create-linode-with-vpc.spec.ts index 238be908e06..44041fc9dc6 100644 --- a/packages/manager/cypress/e2e/core/linodes/create-linode-with-vpc.spec.ts +++ b/packages/manager/cypress/e2e/core/linodes/create-linode-with-vpc.spec.ts @@ -4,10 +4,6 @@ import { subnetFactory, vpcFactory, } from 'src/factories'; -import { - mockAppendFeatureFlags, - mockGetFeatureFlagClientstream, -} from 'support/intercepts/feature-flags'; import { mockCreateLinode, mockGetLinodeDetails, @@ -21,7 +17,6 @@ import { } from 'support/intercepts/vpc'; import { ui } from 'support/ui'; import { linodeCreatePage, vpcCreateDrawer } from 'support/ui/pages'; -import { makeFeatureFlagData } from 'support/util/feature-flags'; import { randomIp, randomLabel, @@ -32,14 +27,6 @@ import { import { chooseRegion } from 'support/util/regions'; describe('Create Linode with VPCs', () => { - // TODO Remove feature flag mocks when `linodeCreateRefactor` flag is retired. - beforeEach(() => { - mockAppendFeatureFlags({ - linodeCreateRefactor: makeFeatureFlagData(true), - }); - mockGetFeatureFlagClientstream(); - }); - /* * - Confirms UI flow to create a Linode with an existing VPC assigned using mock API data. * - Confirms that VPC assignment is reflected in create summary section. diff --git a/packages/manager/cypress/e2e/core/linodes/create-linode.spec.ts b/packages/manager/cypress/e2e/core/linodes/create-linode.spec.ts index bf86857ff8c..f57807153d6 100644 --- a/packages/manager/cypress/e2e/core/linodes/create-linode.spec.ts +++ b/packages/manager/cypress/e2e/core/linodes/create-linode.spec.ts @@ -9,15 +9,10 @@ import { LINODE_CREATE_TIMEOUT } from 'support/constants/linodes'; import { cleanUp } from 'support/util/cleanup'; import { linodeCreatePage } from 'support/ui/pages'; import { authenticate } from 'support/api/authentication'; -import { - mockAppendFeatureFlags, - mockGetFeatureFlagClientstream, -} from 'support/intercepts/feature-flags'; import { interceptCreateLinode, mockCreateLinodeError, } from 'support/intercepts/linodes'; -import { makeFeatureFlagData } from 'support/util/feature-flags'; import { interceptGetProfile } from 'support/intercepts/profile'; import { Region, VLAN, Config, Disk } from '@linode/api-v4'; import { getRegionById } from 'support/util/regions'; @@ -62,15 +57,6 @@ describe('Create Linode', () => { cleanUp('ssh-keys'); }); - // Enable the `linodeCreateRefactor` feature flag. - // TODO Delete these mocks once `linodeCreateRefactor` feature flag is retired. - beforeEach(() => { - mockAppendFeatureFlags({ - linodeCreateRefactor: makeFeatureFlagData(true), - }); - mockGetFeatureFlagClientstream(); - }); - /* * End-to-end tests to create Linodes for each available plan type. */ diff --git a/packages/manager/cypress/e2e/core/linodes/legacy-create-linode.spec.ts b/packages/manager/cypress/e2e/core/linodes/legacy-create-linode.spec.ts deleted file mode 100644 index 48ece191c37..00000000000 --- a/packages/manager/cypress/e2e/core/linodes/legacy-create-linode.spec.ts +++ /dev/null @@ -1,609 +0,0 @@ -/** - * @file Integration tests and end-to-end tests for legacy Linode Create flow. - */ -// TODO Delete this test file when `linodeCreateRefactor` feature flag is retired. -// Move out any tests (e.g. region select test) for flows that aren't covered by new tests in the meantime. - -import { - containsVisible, - fbtClick, - fbtVisible, - getClick, - getVisible, -} from 'support/helpers'; -import { ui } from 'support/ui'; -import { randomString, randomLabel, randomNumber } from 'support/util/random'; -import { chooseRegion } from 'support/util/regions'; -import { getRegionById } from 'support/util/regions'; -import { - accountFactory, - subnetFactory, - vpcFactory, - linodeFactory, - linodeConfigFactory, - regionFactory, - VLANFactory, - LinodeConfigInterfaceFactory, - LinodeConfigInterfaceFactoryWithVPC, -} from '@src/factories'; -import { authenticate } from 'support/api/authentication'; -import { cleanUp } from 'support/util/cleanup'; -import { mockGetRegions } from 'support/intercepts/regions'; -import { - dcPricingPlanPlaceholder, - dcPricingMockLinodeTypes, - dcPricingDocsLabel, - dcPricingDocsUrl, -} from 'support/constants/dc-specific-pricing'; -import { mockGetVLANs } from 'support/intercepts/vlans'; -import { mockGetLinodeConfigs } from 'support/intercepts/configs'; -import { - interceptCreateLinode, - mockCreateLinode, - mockGetLinodeType, - mockGetLinodeTypes, - mockGetLinodeDisks, - mockGetLinodeVolumes, -} from 'support/intercepts/linodes'; -import { mockGetAccount } from 'support/intercepts/account'; -import { mockGetVPC, mockGetVPCs } from 'support/intercepts/vpc'; -import { - mockAppendFeatureFlags, - mockGetFeatureFlagClientstream, -} from 'support/intercepts/feature-flags'; -import { makeFeatureFlagData } from 'support/util/feature-flags'; -import { - checkboxTestId, - headerTestId, -} from 'src/components/Encryption/Encryption'; -import { extendRegion } from 'support/util/regions'; - -import type { Config, VLAN, Disk, Region } from '@linode/api-v4'; -import type { ExtendedRegion } from 'support/util/regions'; - -const mockRegions: ExtendedRegion[] = [ - extendRegion( - regionFactory.build({ - capabilities: ['Linodes'], - country: 'uk', - id: 'eu-west', - label: 'London, UK', - }) - ), - extendRegion( - regionFactory.build({ - capabilities: ['Linodes'], - country: 'sg', - id: 'ap-south', - label: 'Singapore, SG', - }) - ), - extendRegion( - regionFactory.build({ - capabilities: ['Linodes'], - id: 'us-east', - label: 'Newark, NJ', - }) - ), - extendRegion( - regionFactory.build({ - capabilities: ['Linodes'], - id: 'us-central', - label: 'Dallas, TX', - }) - ), -]; - -authenticate(); -describe('create linode', () => { - before(() => { - cleanUp('linodes'); - }); - - beforeEach(() => { - mockAppendFeatureFlags({ - linodeCreateRefactor: makeFeatureFlagData(false), - apicliDxToolsAdditions: makeFeatureFlagData(false), - }); - }); - - /* - * Region select test. - * - * TODO: Cypress - * Move this to cypress component testing once the setup is complete - see https://github.com/linode/manager/pull/10134 - * - * - Confirms that region select dropdown is visible and interactive. - * - Confirms that region select dropdown is populated with expected regions. - * - Confirms that region select dropdown is sorted alphabetically by region, with North America first. - * - Confirms that region select dropdown is populated with expected DCs, sorted alphabetically. - */ - it('region select', () => { - mockGetRegions(mockRegions).as('getRegions'); - - cy.visitWithLogin('linodes/create'); - - cy.wait(['@getRegions']); - - // Confirm that region select dropdown is visible and interactive. - ui.regionSelect.find().click(); - cy.get('[data-qa-autocomplete-popper="true"]').should('be.visible'); - - // Confirm that region select dropdown are grouped by region, - // sorted alphabetically, with North America first. - cy.get('.MuiAutocomplete-groupLabel') - .should('have.length', 3) - .should((group) => { - expect(group[0]).to.contain('North America'); - expect(group[1]).to.contain('Asia'); - expect(group[2]).to.contain('Europe'); - }); - - // Confirm that region select dropdown is populated with expected regions, sorted alphabetically. - cy.get('[data-qa-option]').should('exist').should('have.length', 4); - mockRegions.forEach((region) => { - cy.get('[data-qa-option]').contains(region.label); - }); - - // Select an option - cy.findByTestId('eu-west').click(); - // Confirm the popper is closed - cy.get('[data-qa-autocomplete-popper="true"]').should('not.exist'); - // Confirm that the selected region is displayed in the input field. - cy.get('[data-testid="textfield-input"]').should( - 'have.value', - 'UK, London (eu-west)' - ); - - // Confirm that selecting a valid region updates the Plan Selection panel. - expect(cy.get('[data-testid="table-row-empty"]').should('not.exist')); - }); - - it('creates a nanode', () => { - const rootpass = randomString(32); - const linodeLabel = randomLabel(); - // intercept request - cy.visitWithLogin('/linodes/create'); - cy.get('[data-qa-deploy-linode]'); - interceptCreateLinode().as('linodeCreated'); - cy.get('[data-qa-header="Create"]').should('have.text', 'Create'); - ui.regionSelect.find().click(); - ui.regionSelect - .findItemByRegionLabel( - chooseRegion({ capabilities: ['Vlans', 'Linodes'] }).label - ) - .click(); - fbtClick('Shared CPU'); - getClick('[id="g6-nanode-1"]'); - getClick('#linode-label').clear().type(linodeLabel); - cy.get('#root-password').type(rootpass); - getClick('[data-qa-deploy-linode]'); - cy.wait('@linodeCreated').its('response.statusCode').should('eq', 200); - ui.toast.assertMessage(`Your Linode ${linodeLabel} is being created.`); - containsVisible('PROVISIONING'); - fbtVisible(linodeLabel); - cy.contains('RUNNING', { timeout: 300000 }).should('be.visible'); - }); - - it('creates a linode via CLI', () => { - const linodeLabel = randomLabel(); - const linodePass = randomString(32); - const linodeRegion = chooseRegion(); - - cy.visitWithLogin('/linodes/create'); - - ui.regionSelect.find().click(); - ui.autocompletePopper - .findByTitle(`${linodeRegion.label} (${linodeRegion.id})`) - .should('exist') - .click(); - - cy.get('[id="g6-dedicated-2"]').click(); - - cy.findByLabelText('Linode Label') - .should('be.visible') - .should('be.enabled') - .clear() - .type(linodeLabel); - - cy.findByLabelText('Root Password') - .should('be.visible') - .should('be.enabled') - .type(linodePass); - - ui.button - .findByTitle('Create using command line') - .should('be.visible') - .should('be.enabled') - .click(); - - ui.dialog - .findByTitle('Create Linode') - .should('be.visible') - .within(() => { - // Switch to cURL view if necessary. - cy.findByText('cURL') - .should('be.visible') - .should('have.attr', 'data-selected'); - - // Confirm that cURL command has expected details. - [ - `"region": "${linodeRegion.id}"`, - `"type": "g6-dedicated-2"`, - `"label": "${linodeLabel}"`, - `"root_pass": "${linodePass}"`, - '"booted": true', - ].forEach((line: string) => - cy.findByText(line, { exact: false }).should('be.visible') - ); - - cy.findByText('Linode CLI').should('be.visible').click(); - - [ - `--region ${linodeRegion.id}`, - '--type g6-dedicated-2', - `--label ${linodeLabel}`, - `--root_pass ${linodePass}`, - `--booted true`, - ].forEach((line: string) => cy.contains(line).should('be.visible')); - - ui.buttonGroup - .findButtonByTitle('Close') - .should('be.visible') - .should('be.enabled') - .click(); - }); - }); - - /* - * - Confirms DC-specific pricing UI flow works as expected during Linode creation. - * - Confirms that pricing docs link is shown in "Region" section. - * - Confirms that backups pricing is correct when selecting a region with a different price structure. - */ - it('shows DC-specific pricing information during create flow', () => { - const rootpass = randomString(32); - const linodeLabel = randomLabel(); - const initialRegion = getRegionById('us-west'); - const newRegion = getRegionById('us-east'); - - const mockLinode = linodeFactory.build({ - label: linodeLabel, - region: initialRegion.id, - type: dcPricingMockLinodeTypes[0].id, - }); - - const currentPrice = dcPricingMockLinodeTypes[0].region_prices.find( - (regionPrice) => regionPrice.id === initialRegion.id - )!; - const currentBackupPrice = dcPricingMockLinodeTypes[0].addons.backups.region_prices.find( - (regionPrice) => regionPrice.id === initialRegion.id - )!; - const newPrice = dcPricingMockLinodeTypes[1].region_prices.find( - (linodeType) => linodeType.id === newRegion.id - )!; - const newBackupPrice = dcPricingMockLinodeTypes[1].addons.backups.region_prices.find( - (regionPrice) => regionPrice.id === newRegion.id - )!; - - // Mock requests to get individual types. - mockGetLinodeType(dcPricingMockLinodeTypes[0]); - mockGetLinodeType(dcPricingMockLinodeTypes[1]); - mockGetLinodeTypes(dcPricingMockLinodeTypes).as('getLinodeTypes'); - - // intercept request - cy.visitWithLogin('/linodes/create'); - cy.wait(['@getLinodeTypes']); - - mockCreateLinode(mockLinode).as('linodeCreated'); - cy.get('[data-qa-header="Create"]').should('have.text', 'Create'); - getClick('[data-qa-deploy-linode]'); - - // A message is shown to instruct users to select a region in order to view plans and prices - cy.get('[data-qa-tp="Linode Plan"]').should( - 'contain.text', - 'Plan is required.' - ); - cy.get('[data-qa-tp="Linode Plan"]').should( - 'contain.text', - dcPricingPlanPlaceholder - ); - - // Check the 'Backups' add on - cy.get('[data-testid="backups"]').should('be.visible').click(); - ui.regionSelect.find().click(); - ui.regionSelect.findItemByRegionLabel(initialRegion.label).click(); - fbtClick('Shared CPU'); - getClick(`[id="${dcPricingMockLinodeTypes[0].id}"]`); - // Confirm that the backup prices are displayed as expected. - cy.get('[data-qa-add-ons="true"]') - .eq(1) - .within(() => { - cy.findByText(`$${currentBackupPrice.monthly}`).should('be.visible'); - cy.findByText('per month').should('be.visible'); - }); - // Confirm that the checkout summary at the bottom of the page reflects the correct price. - cy.get('[data-qa-summary="true"]').within(() => { - cy.findByText(`$${currentPrice.monthly!.toFixed(2)}/month`).should( - 'be.visible' - ); - cy.findByText('Backups').should('be.visible'); - cy.findByText(`$${currentBackupPrice.monthly!.toFixed(2)}/month`).should( - 'be.visible' - ); - }); - - // Confirm there is a docs link to the pricing page. - cy.findByText(dcPricingDocsLabel) - .should('be.visible') - .should('have.attr', 'href', dcPricingDocsUrl); - - ui.regionSelect.find().click().type(`${newRegion.label} {enter}`); - fbtClick('Shared CPU'); - getClick(`[id="${dcPricingMockLinodeTypes[0].id}"]`); - // Confirm that the backup prices are displayed as expected. - cy.get('[data-qa-add-ons="true"]') - .eq(1) - .within(() => { - cy.findByText(`$${newBackupPrice.monthly}`).should('be.visible'); - cy.findByText('per month').should('be.visible'); - }); - // Confirms that the summary updates to reflect price changes if the user changes their region and plan selection. - cy.get('[data-qa-summary="true"]').within(() => { - cy.findByText(`$${newPrice.monthly!.toFixed(2)}/month`).should( - 'be.visible' - ); - cy.findByText('Backups').should('be.visible'); - cy.findByText(`$${newBackupPrice.monthly!.toFixed(2)}/month`).should( - 'be.visible' - ); - }); - - getClick('#linode-label').clear().type(linodeLabel); - cy.get('#root-password').type(rootpass); - getClick('[data-qa-deploy-linode]'); - cy.wait('@linodeCreated').its('response.statusCode').should('eq', 200); - fbtVisible(linodeLabel); - cy.contains('RUNNING', { timeout: 300000 }).should('be.visible'); - }); - - it("prevents a VPC from being assigned in a region that doesn't support VPCs during the Linode Create flow", () => { - const region: Region = getRegionById('us-southeast'); - const mockNoVPCRegion = regionFactory.build({ - id: region.id, - label: region.label, - capabilities: ['Linodes'], - }); - - // Mock requests to get individual types. - mockGetLinodeType(dcPricingMockLinodeTypes[0]); - mockGetLinodeType(dcPricingMockLinodeTypes[1]); - mockGetLinodeTypes(dcPricingMockLinodeTypes).as('getLinodeTypes'); - mockGetRegions([mockNoVPCRegion]).as('getRegions'); - - // intercept request - cy.visitWithLogin('/linodes/create'); - cy.wait('@getLinodeTypes'); - - cy.get('[data-qa-header="Create"]').should('have.text', 'Create'); - - // Check the 'Backups' add on - cy.get('[data-testid="backups"]').should('be.visible').click(); - ui.regionSelect.find().click().type(`${region.label} {enter}`); - fbtClick('Shared CPU'); - getClick(`[id="${dcPricingMockLinodeTypes[0].id}"]`); - - // the "VPC" section is present - getVisible('[data-testid="vpc-panel"]').within(() => { - containsVisible( - 'Allow Linode to communicate in an isolated environment.' - ); - // Helper text appears if VPC is not available in selected region. - containsVisible('VPC is not available in the selected region.'); - }); - }); - - it('assigns a VPC to the linode during create flow', () => { - const rootpass = randomString(32); - const linodeLabel = randomLabel(); - const region: Region = getRegionById('us-southeast'); - const diskLabel: string = 'Debian 10 Disk'; - const mockLinode = linodeFactory.build({ - label: linodeLabel, - region: region.id, - type: dcPricingMockLinodeTypes[0].id, - }); - const mockVLANs: VLAN[] = VLANFactory.buildList(2); - const mockSubnet = subnetFactory.build({ - id: randomNumber(2), - label: randomLabel(), - }); - const mockVPC = vpcFactory.build({ - id: randomNumber(), - region: 'us-southeast', - subnets: [mockSubnet], - label: randomLabel(), - }); - const mockVPCRegion = regionFactory.build({ - id: region.id, - label: region.label, - capabilities: ['Linodes', 'VPCs', 'Vlans'], - }); - const mockPublicConfigInterface = LinodeConfigInterfaceFactory.build({ - ipam_address: null, - purpose: 'public', - }); - const mockVlanConfigInterface = LinodeConfigInterfaceFactory.build(); - const mockVpcConfigInterface = LinodeConfigInterfaceFactoryWithVPC.build({ - vpc_id: mockVPC.id, - purpose: 'vpc', - active: true, - }); - const mockConfig: Config = linodeConfigFactory.build({ - id: randomNumber(), - interfaces: [ - // The order of this array is significant. Index 0 (eth0) should be public. - mockPublicConfigInterface, - mockVlanConfigInterface, - mockVpcConfigInterface, - ], - }); - const mockDisks: Disk[] = [ - { - id: 44311273, - status: 'ready', - label: diskLabel, - created: '2020-08-21T17:26:14', - updated: '2020-08-21T17:26:30', - filesystem: 'ext4', - size: 81408, - }, - { - id: 44311274, - status: 'ready', - label: '512 MB Swap Image', - created: '2020-08-21T17:26:14', - updated: '2020-08-21T17:26:31', - filesystem: 'swap', - size: 512, - }, - ]; - - // Mock requests to get individual types. - mockGetLinodeType(dcPricingMockLinodeTypes[0]); - mockGetLinodeType(dcPricingMockLinodeTypes[1]); - mockGetLinodeTypes(dcPricingMockLinodeTypes).as('getLinodeTypes'); - - mockAppendFeatureFlags({ - apicliDxToolsAdditions: makeFeatureFlagData(false), - }).as('getFeatureFlags'); - mockGetFeatureFlagClientstream().as('getClientStream'); - - mockGetRegions([mockVPCRegion]).as('getRegions'); - - mockGetVLANs(mockVLANs); - mockGetVPC(mockVPC).as('getVPC'); - mockGetVPCs([mockVPC]).as('getVPCs'); - mockCreateLinode(mockLinode).as('linodeCreated'); - mockGetLinodeConfigs(mockLinode.id, [mockConfig]).as('getLinodeConfigs'); - mockGetLinodeDisks(mockLinode.id, mockDisks).as('getDisks'); - mockGetLinodeVolumes(mockLinode.id, []).as('getVolumes'); - - // intercept request - cy.visitWithLogin('/linodes/create'); - cy.wait(['@getLinodeTypes', '@getVPCs']); - - cy.get('[data-qa-header="Create"]').should('have.text', 'Create'); - - // Check the 'Backups' add on - cy.get('[data-testid="backups"]').should('be.visible').click(); - ui.regionSelect.find().click().type(`${region.label} {enter}`); - fbtClick('Shared CPU'); - getClick(`[id="${dcPricingMockLinodeTypes[0].id}"]`); - - // the "VPC" section is present, and the VPC in the same region of - // the linode can be selected. - getVisible('[data-testid="vpc-panel"]').within(() => { - containsVisible('Assign this Linode to an existing VPC.'); - // select VPC - cy.findByLabelText('Assign VPC') - .should('be.visible') - .focus() - .clear() - .type(`${mockVPC.label}{downArrow}{enter}`); - // select subnet - cy.findByPlaceholderText('Select Subnet') - .should('be.visible') - .type(`${mockSubnet.label}{downArrow}{enter}`); - }); - - getClick('#linode-label').clear().type(linodeLabel); - cy.get('#root-password').type(rootpass); - - ui.button.findByTitle('Create Linode').click(); - - cy.wait('@linodeCreated').its('response.statusCode').should('eq', 200); - fbtVisible(linodeLabel); - cy.contains('RUNNING', { timeout: 300000 }).should('be.visible'); - - fbtClick('Configurations'); - //cy.wait(['@getLinodeConfigs', '@getVPC', '@getDisks', '@getVolumes']); - - // Confirm that VLAN and VPC have been assigned. - cy.findByLabelText('List of Configurations').within(() => { - cy.get('tr').should('have.length', 2); - containsVisible(`${mockConfig.label} – GRUB 2`); - containsVisible('eth0 – Public Internet'); - containsVisible(`eth2 – VPC: ${mockVPC.label}`); - }); - }); - - it('should not have a "Disk Encryption" section visible if the feature flag is off and user does not have capability', () => { - // Mock feature flag -- @TODO LDE: Remove feature flag once LDE is fully rolled out - mockAppendFeatureFlags({ - linodeDiskEncryption: makeFeatureFlagData(false), - apicliDxToolsAdditions: makeFeatureFlagData(false), - }).as('getFeatureFlags'); - - // Mock account response - const mockAccount = accountFactory.build({ - capabilities: ['Linodes'], - }); - - mockGetAccount(mockAccount).as('getAccount'); - - // intercept request - cy.visitWithLogin('/linodes/create'); - cy.wait(['@getFeatureFlags', '@getAccount']); - - // Check if section is visible - cy.get(`[data-testid=${headerTestId}]`).should('not.exist'); - }); - - it('should have a "Disk Encryption" section visible if feature flag is on and user has the capability', () => { - // Mock feature flag -- @TODO LDE: Remove feature flag once LDE is fully rolled out - mockAppendFeatureFlags({ - linodeDiskEncryption: makeFeatureFlagData(true), - apicliDxToolsAdditions: makeFeatureFlagData(false), - }).as('getFeatureFlags'); - - // Mock account response - const mockAccount = accountFactory.build({ - capabilities: ['Linodes', 'Disk Encryption'], - }); - - const mockRegion = regionFactory.build({ - capabilities: ['Linodes', 'Disk Encryption'], - }); - - const mockRegionWithoutDiskEncryption = regionFactory.build({ - capabilities: ['Linodes'], - }); - - const mockRegions = [mockRegion, mockRegionWithoutDiskEncryption]; - - mockGetAccount(mockAccount).as('getAccount'); - mockGetRegions(mockRegions); - - // intercept request - cy.visitWithLogin('/linodes/create'); - cy.wait(['@getFeatureFlags', '@getAccount']); - - // Check if section is visible - cy.get(`[data-testid="${headerTestId}"]`).should('exist'); - - // "Encrypt Disk" checkbox should be disabled if a region that does not support LDE is selected - ui.regionSelect.find().click(); - ui.select - .findItemByText( - `${mockRegionWithoutDiskEncryption.label} (${mockRegionWithoutDiskEncryption.id})` - ) - .click(); - - cy.get(`[data-testid="${checkboxTestId}"]`).should('be.disabled'); - - ui.regionSelect.find().click(); - ui.select.findItemByText(`${mockRegion.label} (${mockRegion.id})`).click(); - - cy.get(`[data-testid="${checkboxTestId}"]`).should('be.enabled'); - }); -}); diff --git a/packages/manager/cypress/e2e/core/oneClickApps/one-click-apps.spec.ts b/packages/manager/cypress/e2e/core/oneClickApps/one-click-apps.spec.ts index f7aa759ec34..f453f6b7153 100644 --- a/packages/manager/cypress/e2e/core/oneClickApps/one-click-apps.spec.ts +++ b/packages/manager/cypress/e2e/core/oneClickApps/one-click-apps.spec.ts @@ -1,37 +1,27 @@ -import { containsClick, containsVisible } from 'support/helpers'; +import { containsVisible } from 'support/helpers'; import { ui } from 'support/ui'; -import { authenticate } from 'support/api/authentication'; -import { cleanUp } from 'support/util/cleanup'; import { interceptGetStackScripts, + mockGetStackScript, mockGetStackScripts, } from 'support/intercepts/stackscripts'; -import { interceptCreateLinode } from 'support/intercepts/linodes'; +import { mockCreateLinode } from 'support/intercepts/linodes'; import { filterOneClickApps, handleAppLabel, } from 'src/features/Linodes/LinodesCreate/utilities'; import { randomLabel, randomString } from 'support/util/random'; import { chooseRegion } from 'support/util/regions'; -import { - mockAppendFeatureFlags, - mockGetFeatureFlagClientstream, -} from 'support/intercepts/feature-flags'; -import { makeFeatureFlagData } from 'support/util/feature-flags'; import { mapStackScriptLabelToOCA } from 'src/features/OneClickApps/utils'; import { stackScriptFactory } from 'src/factories/stackscripts'; import { oneClickApps } from 'src/features/OneClickApps/oneClickAppsv2'; import type { StackScript } from '@linode/api-v4'; import type { OCA } from '@src/features/OneClickApps/types'; - -authenticate(); +import { imageFactory, linodeFactory } from 'src/factories'; +import { mockGetAllImages } from 'support/intercepts/images'; describe('OneClick Apps (OCA)', () => { - before(() => { - cleanUp(['linodes']); - }); - it('Lists all the OneClick Apps', () => { interceptGetStackScripts().as('getStackScripts'); @@ -123,9 +113,19 @@ describe('OneClick Apps (OCA)', () => { }); it('Deploys a Linode from a One Click App', () => { - const stackscriptId = 401709; - const stackScripts = stackScriptFactory.build({ - id: stackscriptId, + const images = [ + imageFactory.build({ + id: 'linode/ubuntu22.04', + label: 'Ubuntu 20.04', + }), + imageFactory.build({ + id: 'linode/debian11', + label: 'Debian 11', + }), + ]; + + const stackscript = stackScriptFactory.build({ + id: 0, username: 'linode', user_gravatar_id: '9d4d301385af69ceb7ad658aad09c142', label: 'E2E Test App', @@ -160,26 +160,25 @@ describe('OneClick Apps (OCA)', () => { ], }); - const firstName = randomLabel(); - const password = randomString(16); - const image = 'linode/ubuntu22.04'; const rootPassword = randomString(16); - const region = chooseRegion({ capabilities: ['Vlans'] }); + const region = chooseRegion(); const linodeLabel = randomLabel(); + + // UDF values + const firstName = randomLabel(); + const password = randomString(16); const levelName = 'Get the enderman!'; - mockGetStackScripts([stackScripts]).as('getStackScripts'); - mockAppendFeatureFlags({ - linodeCreateRefactor: makeFeatureFlagData(false), - oneClickApps: makeFeatureFlagData({ - 401709: 'E2E Test App', - }), - }).as('getFeatureFlags'); - mockGetFeatureFlagClientstream().as('getClientStream'); + const linode = linodeFactory.build({ + label: linodeLabel, + }); + + mockGetAllImages(images); + mockGetStackScripts([stackscript]).as('getStackScripts'); + mockGetStackScript(stackscript.id, stackscript); cy.visitWithLogin(`/linodes/create?type=One-Click`); - cy.wait('@getFeatureFlags'); cy.wait('@getStackScripts'); cy.findByTestId('one-click-apps-container').within(() => { @@ -188,40 +187,43 @@ describe('OneClick Apps (OCA)', () => { // Check that the app is listed and select it cy.get('[data-qa-selection-card="true"]').should('have.length', 3); - cy.get(`[id=app-${stackscriptId}]`).first().should('be.visible').click(); + cy.findAllByText(stackscript.label).first().should('be.visible').click(); }); - // Input the user defined fields - const userFieldId = - "the-username-for-the-linode's-non-root-admin/ssh-user(must-be-lowercase)"; - const passwordFieldId = - "the-password-for-the-linode's-non-root-admin/ssh-user"; - const levelNameFieldId = 'world-name'; + cy.findByLabelText( + "The username for the Linode's non-root admin/SSH user(must be lowercase) (required)" + ) + .should('be.visible') + .click() + .type(firstName); + + cy.findByLabelText( + "The password for the Linode's non-root admin/SSH user (required)" + ) + .should('be.visible') + .click() + .type(password); - cy.findByTestId('user-defined-fields-panel').within(() => { - cy.get(`[id="${userFieldId}"]`) - .should('be.visible') - .click() - .type(`${firstName}{enter}`); - cy.get(`[id="${passwordFieldId}"]`) - .should('be.visible') - .click() - .type(`${password}{enter}`); - cy.get(`[id="${levelNameFieldId}"]`) - .should('be.visible') - .click() - .type(`${levelName}{enter}`); + cy.findByLabelText('World Name (required)') + .should('be.visible') + .click() + .type(levelName); - // Check each field should persist when moving onto another field - cy.get(`[id="${userFieldId}"]`).should('have.value', firstName); - cy.get(`[id="${passwordFieldId}"]`).should('have.value', password); - cy.get(`[id="${levelNameFieldId}"]`).should('have.value', levelName); - }); + // Check each field should persist when moving onto another field + cy.findByLabelText( + "The username for the Linode's non-root admin/SSH user(must be lowercase) (required)" + ).should('have.value', firstName); + + cy.findByLabelText( + "The password for the Linode's non-root admin/SSH user (required)" + ).should('have.value', password); + + cy.findByLabelText('World Name (required)').should('have.value', levelName); // Choose an image - cy.get('[data-qa-enhanced-select="Choose an image"]').within(() => { - containsClick('Choose an image').type(`${image}{enter}`); - }); + cy.findByPlaceholderText('Choose an image') + .click() + .type('{downArrow}{enter}'); // Choose a region ui.regionSelect.find().click().type(`${region.id}{enter}`); @@ -237,14 +239,14 @@ describe('OneClick Apps (OCA)', () => { cy.findByText('Linode Label') .should('be.visible') .click() - .type('{selectAll}{backspace}') .type(linodeLabel); // Choose a Root Password cy.get('[id="root-password"]').type(rootPassword); // Create the Linode - interceptCreateLinode().as('createLinode'); + mockCreateLinode(linode).as('createLinode'); + ui.button .findByTitle('Create Linode') .should('be.visible') @@ -252,6 +254,7 @@ describe('OneClick Apps (OCA)', () => { .click(); cy.wait('@createLinode'); - ui.toast.assertMessage(`Your Linode ${linodeLabel} is being created.`); + + ui.toast.assertMessage(`Your Linode ${linode.label} is being created.`); }); }); diff --git a/packages/manager/cypress/e2e/core/placementGroups/create-linode-with-placement-groups.spec.ts b/packages/manager/cypress/e2e/core/placementGroups/create-linode-with-placement-groups.spec.ts index b1573679bdc..2484db5c322 100644 --- a/packages/manager/cypress/e2e/core/placementGroups/create-linode-with-placement-groups.spec.ts +++ b/packages/manager/cypress/e2e/core/placementGroups/create-linode-with-placement-groups.spec.ts @@ -1,8 +1,3 @@ -import { - mockAppendFeatureFlags, - mockGetFeatureFlagClientstream, -} from 'support/intercepts/feature-flags'; -import { makeFeatureFlagData } from 'support/util/feature-flags'; import { mockGetAccount } from 'support/intercepts/account'; import { accountFactory, @@ -25,8 +20,6 @@ import { CANNOT_CHANGE_PLACEMENT_GROUP_POLICY_MESSAGE } from 'src/features/Place import { linodeCreatePage } from 'support/ui/pages'; import { extendRegion } from 'support/util/regions'; -import type { Flags } from 'src/featureFlags'; - const mockAccount = accountFactory.build(); const mockNewarkRegion = extendRegion( @@ -53,13 +46,6 @@ describe('Linode create flow with Placement Group', () => { beforeEach(() => { mockGetAccount(mockAccount); mockGetRegions(mockRegions).as('getRegions'); - // TODO Remove feature flag mocks when `placementGroups` flag is retired. - mockAppendFeatureFlags({ - linodeCreateRefactor: makeFeatureFlagData( - false - ), - }); - mockGetFeatureFlagClientstream(); }); /* @@ -194,16 +180,16 @@ describe('Linode create flow with Placement Group', () => { }); // Confirm the Placement group assignment is accounted for in the summary. - cy.get('[data-qa-summary="true"]').within(() => { - cy.findByText('Assigned to Placement Group').should('be.visible'); - }); + cy.findByText('Assigned to Placement Group') + .scrollIntoView() + .should('be.visible'); // Type in a label, password and submit the form. mockCreateLinode(mockLinode).as('createLinode'); cy.get('#linode-label').clear().type('linode-with-placement-group'); cy.get('#root-password').type(randomString(32)); - cy.get('[data-qa-deploy-linode]').click(); + cy.findByText('Create Linode').should('be.enabled').click(); // Wait for outgoing API request and confirm that payload contains expected data. cy.wait('@createLinode').then((xhr) => { @@ -265,9 +251,9 @@ describe('Linode create flow with Placement Group', () => { .click(); // Confirm the Placement group assignment is accounted for in the summary. - cy.get('[data-qa-summary="true"]').within(() => { - cy.findByText('Assigned to Placement Group').should('be.visible'); - }); + cy.findByText('Assigned to Placement Group') + .scrollIntoView() + .should('be.visible'); // Create Linode and confirm contents of outgoing API request payload. ui.button diff --git a/packages/manager/src/features/Linodes/LinodeCreatev2/Addons/Addons.tsx b/packages/manager/src/features/Linodes/LinodeCreatev2/Addons/Addons.tsx index de19fca6b22..a8652f9eeec 100644 --- a/packages/manager/src/features/Linodes/LinodeCreatev2/Addons/Addons.tsx +++ b/packages/manager/src/features/Linodes/LinodeCreatev2/Addons/Addons.tsx @@ -28,7 +28,7 @@ export const Addons = () => { selectedRegion?.site_type === 'edge'; return ( - + Add-ons {isDistributedRegionSelected && ( diff --git a/packages/manager/src/features/OneClickApps/oneClickAppsv2.ts b/packages/manager/src/features/OneClickApps/oneClickAppsv2.ts index 96f0e14d380..4dbb5d87fc9 100644 --- a/packages/manager/src/features/OneClickApps/oneClickAppsv2.ts +++ b/packages/manager/src/features/OneClickApps/oneClickAppsv2.ts @@ -9,11 +9,10 @@ import type { OCA } from './types'; * for it to be visible to users. */ export const oneClickApps: Record = { - 0: { - ...oneClickAppFactory.build({ - name: 'E2E Test App', - }), - }, + 0: oneClickAppFactory.build({ + isNew: true, + name: 'E2E Test App', + }), 401697: { alt_description: 'Popular website content management system.', alt_name: 'CMS: content management system',