Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: [M3-8478] - Fix Cypress StackScript Linode deploy test flake #10826

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-10826-tests-1724431261722.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Tests
---

Resolve StackScript Linode deploy test flake ([#10826](https://github.com/linode/manager/pull/10826))
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
pollLinodeDiskSize,
} from 'support/util/polling';
import { randomLabel, randomString, randomPhrase } from 'support/util/random';
import { interceptGetAccountAvailability } from 'support/intercepts/account';
import {
interceptCreateStackScript,
interceptGetStackScripts,
Expand All @@ -13,7 +14,7 @@ import { interceptCreateLinode } from 'support/intercepts/linodes';
import { ui } from 'support/ui';
import { createLinodeRequestFactory } from 'src/factories';
import { createImage, getLinodeDisks, resizeLinodeDisk } from '@linode/api-v4';
import { chooseRegion } from 'support/util/regions';
import { chooseRegion, getRegionByLabel } from 'support/util/regions';
import { SimpleBackoffMethod } from 'support/util/backoff';
import { cleanUp } from 'support/util/cleanup';
import { createTestLinode } from 'support/util/linodes';
Expand All @@ -32,6 +33,20 @@ const stackScriptErrorNoShebang =
const stackScriptErrorUdfAlphanumeric =
'UDF names can only contain alphanumeric and underscore characters.';

/**
* Sets the StackScript field's value programmatically rather than via simulated typing.
*
* Cypress's typing operation is slow for long strings, so we can save several
* seconds by setting the value directly, then simulating a couple keystrokes.
*
* @param script - Script contents to input.
*/
const inputStackScript = (script: string) => {
cy.get('[data-qa-textfield-label="Script"]').should('be.visible').click();

cy.focused().invoke('val', script).type(' {backspace}');
};

/**
* Fills out the StackScript creation form.
*
Expand Down Expand Up @@ -66,11 +81,8 @@ const fillOutStackscriptForm = (

cy.findByText(`${targetImage}`).should('be.visible').click();

// Insert a script with invalid UDF data.
cy.get('[data-qa-textfield-label="Script"]')
.should('be.visible')
.click()
.type(script);
// Insert a script.
inputStackScript(script);
};

/**
Expand All @@ -84,9 +96,14 @@ const fillOutStackscriptForm = (
*/
const fillOutLinodeForm = (label: string, regionName: string) => {
const password = randomString(32);
const region = getRegionByLabel(regionName);

ui.regionSelect.find().click();
ui.regionSelect.findItemByRegionLabel(regionName).click();
ui.regionSelect
.findItemByRegionLabel(regionName)
.should('be.visible')
.click();
ui.regionSelect.find().should('have.value', `${region.label} (${region.id})`);

cy.findByText('Linode Label')
.should('be.visible')
Expand Down Expand Up @@ -173,6 +190,7 @@ describe('Create stackscripts', () => {
interceptCreateStackScript().as('createStackScript');
interceptGetStackScripts().as('getStackScripts');
interceptCreateLinode().as('createLinode');
interceptGetAccountAvailability().as('getAvailability');

cy.visitWithLogin('/stackscripts/create');

Expand All @@ -196,11 +214,7 @@ describe('Create stackscripts', () => {
cy.findByText(stackScriptErrorNoShebang).should('be.visible');

cy.fixture(stackscriptUdfInvalidPath).then((stackScriptUdfInvalid) => {
cy.get('[data-qa-textfield-label="Script"]')
.should('be.visible')
.click()
.type('{selectall}{backspace}')
.type(stackScriptUdfInvalid);
inputStackScript(stackScriptUdfInvalid);
});

ui.buttonGroup
Expand All @@ -214,11 +228,7 @@ describe('Create stackscripts', () => {

// Insert a script with valid UDF data and submit StackScript create form.
cy.fixture(stackscriptUdfPath).then((stackScriptUdf) => {
cy.get('[data-qa-textfield-label="Script"]')
.should('be.visible')
.click()
.type('{selectall}{backspace}')
.type(stackScriptUdf);
inputStackScript(stackScriptUdf);
});

ui.buttonGroup
Expand Down Expand Up @@ -249,6 +259,9 @@ describe('Create stackscripts', () => {
.should('be.enabled')
.click();

// Wait for availability to be retrieved before interacting with form.
cy.wait('@getAvailability');

// Fill out Linode creation form, confirm UDF fields behave as expected.
fillOutLinodeForm(linodeLabel, linodeRegion.label);

Expand All @@ -273,7 +286,10 @@ describe('Create stackscripts', () => {

// Confirm that Linode has been created and is provisioning.
cy.findByText(linodeLabel).should('be.visible');
cy.findByText('PROVISIONING').should('be.visible');

// In rare cases, the Linode can provision quicker than this assertion happens,
// so we want to account for cases where it's already booting or even running.
cy.findByText(/(PROVISIONING|BOOTING|RUNNING)/).should('be.visible');
});

/*
Expand Down
9 changes: 9 additions & 0 deletions packages/manager/cypress/support/intercepts/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -678,3 +678,12 @@ export const mockGetMaintenance = (
}
});
};

/**
* Intercepts GET request to fetch account region availability.
*
* @returns Cypress chainable.
*/
export const interceptGetAccountAvailability = (): Cypress.Chainable<null> => {
return cy.intercept('GET', apiMatcher('account/availability*'));
};
16 changes: 11 additions & 5 deletions packages/manager/cypress/support/ui/autocomplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,17 @@ export const autocompletePopper = {
title: string,
options?: SelectorMatcherOptions
): Cypress.Chainable => {
return cy
.document()
.its('body')
.find('[data-qa-autocomplete-popper]')
.findByText(title, options);
return (
cy
.document()
.its('body')
.find('[data-qa-autocomplete-popper]')
.findByText(title, options)
// Scroll to the desired item before yielding.
// Apply a negative top offset to account for cases where the desired
// item may be obscured by the drop-down sticky category heading.
.scrollIntoView({ offset: { left: 0, top: -45 } })
);
},
};

Expand Down
Loading