diff --git a/e2e/config/wdio.conf.js b/e2e/config/wdio.conf.js index 8d1f3f93833..fdd19363e50 100644 --- a/e2e/config/wdio.conf.js +++ b/e2e/config/wdio.conf.js @@ -135,7 +135,7 @@ exports.config = { connectionRetryTimeout: 90000, // // Default request retries count - connectionRetryCount: 3, + connectionRetryCount: 10, // // Initialize the browser instance with a WebdriverIO plugin. The object should have the // plugin name as key and the desired plugin options as properties. Make sure you have diff --git a/e2e/pageobjects/linode-detail/linode-detail-rebuild.page.js b/e2e/pageobjects/linode-detail/linode-detail-rebuild.page.js index 5690da81ad2..60c4ac42ff2 100644 --- a/e2e/pageobjects/linode-detail/linode-detail-rebuild.page.js +++ b/e2e/pageobjects/linode-detail/linode-detail-rebuild.page.js @@ -14,6 +14,7 @@ class Rebuild extends Page { get imageOptions() { return $$(this.imageOption.selector); } get imageError() { return $(`${this.imageSelectSelector}>p`); } get rebuildDescriptionText() { return $('[data-qa-rebuild-desc]'); } + get rebuildConfirmModalButton() { return $('[data-qa-submit-rebuild]') } assertElemsDisplay() { this.rebuildDescriptionText.waitForVisible(constants.wait.normal); @@ -35,8 +36,8 @@ class Rebuild extends Page { } rebuild() { - const toastMessage = 'Linode rebuild started.'; browser.jsClick(this.submit.selector); + browser.jsClick(this.rebuildConfirmModalButton.selector) this.toastDisplays('Linode rebuild started'); } } diff --git a/e2e/pageobjects/linode-detail/linode-detail-settings.page.js b/e2e/pageobjects/linode-detail/linode-detail-settings.page.js index db8d502bd4f..d200c198b29 100644 --- a/e2e/pageobjects/linode-detail/linode-detail-settings.page.js +++ b/e2e/pageobjects/linode-detail/linode-detail-settings.page.js @@ -1,7 +1,7 @@ const { constants } = require('../../constants'); const { generatePassword, - getDistrobutionLabel, + getDistributionLabel } = require('../../utils/common') import Page from '../page'; @@ -82,7 +82,7 @@ class Settings extends Page { imageSelect.waitForVisible(constants.wait.normal); this.diskLabelInput.setValue(diskLabel); imageSelect.click(); - const displayImage = getDistrobutionLabel([imageId])[0]; + const displayImage = getDistributionLabel([imageId])[0]; imageSelect.setValue(displayImage); const imageSelection = `[data-qa-option="linode/${imageId}"]`; $(imageSelection).waitForVisible(constants.wait.normal); @@ -118,8 +118,9 @@ class Settings extends Page { } remove() { - const linodeLabel = browser.getText('[data-qa-label]'); - const confirmTitle = 'Confirm Deletion'; + /** linode label sourced from the editable text H1 in the header */ + const linodeLabel = browser.getText('[data-qa-editable-text]'); + const confirmTitle = `Confirm Deletion of ${linodeLabel}`; const confirmContent = 'Deleting a Linode will result in permanent data loss. Are you sure?'; this.delete.click(); this.deleteDialogTitle.waitForText(); diff --git a/e2e/pageobjects/linode-detail/linode-detail-volume.page.js b/e2e/pageobjects/linode-detail/linode-detail-volume.page.js index a66d638aaf2..6bacff93ba1 100644 --- a/e2e/pageobjects/linode-detail/linode-detail-volume.page.js +++ b/e2e/pageobjects/linode-detail/linode-detail-volume.page.js @@ -236,6 +236,7 @@ export class VolumeDetail extends Page { } detachVolume(volume, detach=true) { + this.selectActionMenuItem(volume, 'Detach'); const dialogTitle = $('[data-qa-dialog-title]'); @@ -389,10 +390,9 @@ export class VolumeDetail extends Page { .map(volume => volume.getAttribute(attribute)); } - hoverVolumeTags(label, volId){ - const id = volId ? volId : this.volumeRow(label).$('..').getAttribute(this.volumeCellElem.selector.slice(1,-1)); - const selector = this.volumeCellElem.selector.replace(']',''); - $(`${selector}="${id}"]>td:nth-child(2)`).moveToObject(); + hoverVolumeTags(label) { + const volumeRow = this.volumeRow(label).$('..'); + volumeRow.$(this.totalTags.selector).moveToObject(); } } diff --git a/e2e/pageobjects/list-domains.page.js b/e2e/pageobjects/list-domains.page.js index ec51a35cac5..cb7de1b5b81 100644 --- a/e2e/pageobjects/list-domains.page.js +++ b/e2e/pageobjects/list-domains.page.js @@ -26,11 +26,12 @@ class ListDomains extends Page { baseElemsDisplay(placeholder) { if (placeholder) { - const placeholderTitle = 'Add a Domain'; + const placeholderTitle = 'Manage your Domains'; + const buttonText = 'Add a Domain'; this.placeholderText.waitForVisible(constants.wait.normal); - expect(this.placeholderText.getText()).toBe(placeholderTitle); - expect(this.createButton.getText()).toBe(placeholderTitle); + expect(this.placeholderText.getText()).toMatch(placeholderTitle); + expect(this.createButton.getText()).toMatch(buttonText); return this; } diff --git a/e2e/pageobjects/list-stackscripts.page.js b/e2e/pageobjects/list-stackscripts.page.js index 9632cb586cc..ccd93c08a8f 100644 --- a/e2e/pageobjects/list-stackscripts.page.js +++ b/e2e/pageobjects/list-stackscripts.page.js @@ -26,7 +26,7 @@ class ListStackScripts extends Page { get stackScriptRows() { return $$('[data-qa-table-row]'); } get stackScriptTitle() { return $('[data-qa-stackscript-title]'); } get stackScriptDeploys() { return $('[data-qa-stackscript-deploys]'); } - get stackScriptCompatibleDistrobutions() { return $('[data-qa-stackscript-images]'); } + get stackScriptCompatibleDistributions() { return $('[data-qa-stackscript-images]'); } get stackScriptActionMenu() { return $('[data-qa-action-menu]'); } get stackScriptActionMenuLink() { return $('[data-qa-action-menu-link]'); } get stackScriptRevision() { return $('[data-qa-stackscript-revision]'); } diff --git a/e2e/pageobjects/page.js b/e2e/pageobjects/page.js index bcae2a5c663..6ec634251e4 100644 --- a/e2e/pageobjects/page.js +++ b/e2e/pageobjects/page.js @@ -35,6 +35,7 @@ export default class Page { get tags() { return $$('[data-qa-tag]'); } get addTag() { return $('[data-qa-add-tag]'); } get deleteTag() { return $('[data-qa-delete-tag]'); } + get totalTags() { return $('[data-qa-total-tags]'); } get helpButton() { return $('[data-qa-help-button]'); } get tagsMultiSelect() { return $('[data-qa-multi-select="Type to choose or create a tag."]'); } get popoverMsg() { return $('[role="tooltip"]'); } @@ -165,19 +166,21 @@ export default class Page { } openActionMenu(actionMenuRow) { - actionMenuRow.$(this.actionMenu.selector).waitForVisible(constants.wait.normal); + browser.waitForVisible(`${actionMenuRow.selector} ${this.actionMenu.selector}`, constants.wait.normal); + // actionMenuRow.$(this.actionMenu.selector).waitForVisible(constants.wait.normal); try { actionMenuRow.$(this.actionMenu.selector).click(); browser.waitUntil(() => { return $$('[data-qa-action-menu-item]').length > 0; - },constants.wait.normal); + }, constants.wait.normal, "Menu items failed to show up"); } catch (e) { - if ( e.Error ){ - actionMenuRow.$(this.actionMenu.selector).click(); + /* Our attempt clicking the action menu bombed, most likely because some + // Element in the UI is covering it. JS Click to force the click instead + */ + browser.jsClick(`${actionMenuRow.selector} ${this.actionMenu.selector}`); browser.waitUntil(() => { return $$('[data-qa-action-menu-item]').length > 0; - },constants.wait.normal); - } + }, constants.wait.normal, "Menu items failed to show up"); } } diff --git a/e2e/pageobjects/stackscripts/stackscript-detail.page.js b/e2e/pageobjects/stackscripts/stackscript-detail.page.js index 52bb65de6a5..fc18343e82d 100644 --- a/e2e/pageobjects/stackscripts/stackscript-detail.page.js +++ b/e2e/pageobjects/stackscripts/stackscript-detail.page.js @@ -42,8 +42,8 @@ class StackScriptDetail extends Page { return $(`${selector}="${stackScriptAuthor}"]`); } - getStackScriptCompatibleDisrobutions(){ - this.compatibleDistrobutions.waitForVisible(constants.wait.normal); + getStackScriptCompatibleDistributions(){ + this.compatibleDistributions.waitForVisible(constants.wait.normal); const distroListText = this.compatibleDistributions.getText(); const cleanText = distroListText.replace('Compatible with: ',''); return cleanText.split(',').map(distro=> distro.trim()); diff --git a/e2e/specs/domains/smoke-list-domains.spec.js b/e2e/specs/domains/smoke-list-domains.spec.js index b46614a8ce5..cc53880ddfd 100644 --- a/e2e/specs/domains/smoke-list-domains.spec.js +++ b/e2e/specs/domains/smoke-list-domains.spec.js @@ -42,6 +42,7 @@ describe('Domains - List Suite', () => { browser.jsClick(`${domainElement} [data-qa-action-menu]`); const expectedMenuItems = [ + 'Edit', 'Clone', 'Remove', 'Edit DNS Records', diff --git a/e2e/specs/linodes/detail/create-volumes.spec.js b/e2e/specs/linodes/detail/create-volumes.spec.js index 76bb962cb46..7c414f96c15 100644 --- a/e2e/specs/linodes/detail/create-volumes.spec.js +++ b/e2e/specs/linodes/detail/create-volumes.spec.js @@ -44,6 +44,7 @@ describe('Linode Detail - Volumes Suite', () => { const checkVolumeDetail = (testVolume,testLinode) => { browser.url(constants.routes.volumes); browser.pause(750); + VolumeDetail.volumeCellElem.waitForVisible(constants.wait.normal); let trimSelector = VolumeDetail.volumeAttachment.selector.replace(']','') const linodeAttachedToCell = `${trimSelector}="${testLinode}"]`; @@ -60,7 +61,7 @@ describe('Linode Detail - Volumes Suite', () => { VolumeDetail.selectActionMenuItemV2(VolumeDetail.volumeCellElem.selector, 'Detach'); VolumeDetail.confirmDetachORDelete(); VolumeDetail.createButton.waitForVisible(constants.wait.long); - expect(VolumeDetail.placeholderText.getText()).toBe('Create a Volume'); + expect(VolumeDetail.placeholderText.getText()).toMatch('Add Block Storage'); } beforeAll(() => { @@ -83,7 +84,7 @@ describe('Linode Detail - Volumes Suite', () => { }); it('should display placeholder text and add a volume button', () => { - expect(VolumeDetail.placeholderText.getText()).toBe('Create a Volume'); + expect(VolumeDetail.placeholderText.getText()).toMatch('Add Block Storage'); expect(VolumeDetail.createButton.isVisible()).toBe(true); }); @@ -197,8 +198,11 @@ describe('Linode Detail - Volumes Suite', () => { it('volume created successfully with tag', () => { + expect(VolumeDetail.volumeCellLabel.getText()).toContain(testVolume.label); expect(VolumeDetail.volumeCellSize.getText()).toContain(testVolume.size); + + VolumeDetail.hoverVolumeTags(testVolume.label); VolumeDetail.checkTagsApplied([testVolume.tags]); }); @@ -215,7 +219,7 @@ describe('Linode Detail - Volumes Suite', () => { }); }); - describe('Attach Existing Volume - Detatch Volume', () => { + describe('Attach Existing Volume - Detach Volume', () => { it('can attach an existing volume', () => { VolumeDetail.createButton.click(); @@ -224,7 +228,7 @@ describe('Linode Detail - Volumes Suite', () => { }); it('volume attached successfully', () => { - VolumeDetail.volumeCellElem.waitForVisible(constants.wait.normal); + VolumeDetail.volumeCellElem.waitForVisible(constants.wait.long); expect(VolumeDetail.volumeCellLabel.getText()).toContain(volumeEast.label); expect(VolumeDetail.volumeCellSize.getText()).toContain('20'); }); diff --git a/e2e/specs/linodes/detail/rebuild.spec.js b/e2e/specs/linodes/detail/rebuild.spec.js index 7753c0764f6..f31d381b23a 100644 --- a/e2e/specs/linodes/detail/rebuild.spec.js +++ b/e2e/specs/linodes/detail/rebuild.spec.js @@ -34,12 +34,14 @@ describe('Linode Detail - Rebuild Suite', () => { Rebuild.rebuildSelect.click(); browser.pause(500); const rebuildOptions = Rebuild.selectOptions.map(options => options.getText()); - expect(rebuildOptions.sort()).toEqual(['From Image','From StackScript']); + expect(rebuildOptions.sort()).toEqual(['From Image', 'From StackScript']); $('body').click(); }); it('should display error on create an image without selecting an image', () => { Rebuild.submit.click(); + browser.waitForVisible(Rebuild.rebuildConfirmModalButton.selector) + Rebuild.rebuildConfirmModalButton.click(); Rebuild.waitForNotice('An image is required.', constants.wait.normal); browser.refresh(); Rebuild.assertElemsDisplay(); @@ -48,8 +50,10 @@ describe('Linode Detail - Rebuild Suite', () => { it('should display error on create image without setting a password', () => { const errorMsg = 'Password cannot be blank.'; Rebuild.selectImage(); - Rebuild.imageOption.waitForVisible(constants.wait.normal,true); + Rebuild.imageOption.waitForVisible(constants.wait.normal, true); Rebuild.submit.click(); + browser.waitForVisible(Rebuild.rebuildConfirmModalButton.selector) + Rebuild.rebuildConfirmModalButton.click(); Rebuild.waitForNotice(errorMsg, constants.wait.normal); browser.refresh(); Rebuild.assertElemsDisplay(); diff --git a/e2e/specs/linodes/detail/resize.spec.js b/e2e/specs/linodes/detail/resize.spec.js index 4defa99551c..011e0136267 100644 --- a/e2e/specs/linodes/detail/resize.spec.js +++ b/e2e/specs/linodes/detail/resize.spec.js @@ -34,7 +34,7 @@ describe('Linode Detail - Resize Suite', () => { }); it('should display toast message on resize', () => { - const toastMsg = 'Linode resize started.'; + const toastMsg = 'Linode queued for resize.'; Resize.planCards[1].click(); browser.waitUntil(() => { diff --git a/e2e/specs/profile/tokens.spec.js b/e2e/specs/profile/tokens.spec.js index 09d0da134e0..4d3f5fbcb6f 100644 --- a/e2e/specs/profile/tokens.spec.js +++ b/e2e/specs/profile/tokens.spec.js @@ -24,7 +24,9 @@ describe('View - Personal Access Tokens', () => { describe('Create - Personal Access Tokens', () => { it('should display create drawer on create', () => { + /** opens the create drawer */ profile.create('token'); + tokenCreateDrawer.baseElemsDisplay(); tokenCreateDrawer.labelTimestamp(timestamp); @@ -60,7 +62,7 @@ describe('View - Personal Access Tokens', () => { const sixMonths = new Date(); sixMonths.setMonth(now.getMonth() + 6); sixMonths.setDate(sixMonths.getDate()); - browser.waitForVisible(token) + browser.waitForVisible(newToken) // $(newToken).waitForVisible(); expect(browser.getText(`${newToken} [data-qa-token-expiry]`)).toContain(sixMonths.toISOString().slice(0,8)); }); @@ -71,10 +73,9 @@ describe('View - Personal Access Tokens', () => { }); it('should display token scopes drawer', () => { - browser.click(`${newToken} [data-qa-action-menu]`); - browser.click('[data-qa-action-menu-item="View Token Scopes"]'); + profile.selectActionMenuItem($(newToken), 'View Token Scopes'); - browser.waitForVisible('[data-qa-row="Account"]'); + browser.waitForVisible('[data-qa-row="Account"]', constants.wait.normal); browser.waitForVisible('[data-qa-close-drawer]'); const accountPermission = $('[data-qa-row="Account"] [data-qa-perm-rw-radio]'); @@ -88,19 +89,18 @@ describe('View - Personal Access Tokens', () => { expect(imagesPermission.getAttribute('data-qa-perm-rw-radio')).toBe('true'); browser.click('[data-qa-close-drawer]'); - - browser.waitForVisible('[data-qa-close-drawer]', constants.wait.normal, true); - browser.waitForExist('[data-qa-drawer]', constants.wait.normal, true); }); describe('Edit - Personal Access Tokens', () => { it('should display edit drawer', () => { - profile.selectActionMenuItem($(newToken), 'Rename Token') + browser.waitForVisible(`${newToken} [data-qa-action-menu]`, constants.wait.normal) + profile.selectActionMenuItem($(newToken), 'Rename Token'); + - expect(tokenCreateDrawer.label.waitForVisible()).toBe(true); + browser.waitForVisible(tokenCreateDrawer.label.selector, constants.wait.normal) expect(tokenCreateDrawer.title.getText()).toBe('Edit Personal Access Token'); - expect(tokenCreateDrawer.submit.isVisible()).toBe(true); - expect(tokenCreateDrawer.cancel.isVisible()).toBe(true); + browser.waitForVisible(tokenCreateDrawer.submit.selector, constants.wait.normal) + browser.waitForVisible(tokenCreateDrawer.cancel.selector, constants.wait.normal) }); it('should update label on edit', () => { @@ -139,7 +139,9 @@ describe('View - Personal Access Tokens', () => { it('should revoke on remove', () => { browser.click(dialogConfirm); profile.tokenBaseElems(); - browser.waitForVisible(updatedSelector, constants.wait.long, true); + /** we've revoked the token and it should not be visible */ + browser.refresh(); + browser.waitForVisible(updatedSelector, constants.wait.normal, true); }); }); }); diff --git a/e2e/specs/profile/update-display.spec.js b/e2e/specs/profile/update-display.spec.js index 773562e5687..9323f6a78fb 100644 --- a/e2e/specs/profile/update-display.spec.js +++ b/e2e/specs/profile/update-display.spec.js @@ -3,58 +3,63 @@ import { updateProfile, getProfile } from '../../utils/common'; import Display from '../../pageobjects/profile/display.page'; describe('Profile - Update Display Settings', () => { - let resetProfileBody; - - beforeAll(() => { - browser.url(constants.routes.profile.view); - const startProfile = getProfile(); - resetProfileBody = { - email: startProfile.email, - timezone: startProfile.timezone - } - }); - - afterAll(() => { - updateProfile(resetProfileBody); - }); - - it('Should display the update display settings view', () => { - Display.baseElementsDisplay(); - }); - - it('Display name should not be editable', () => { - expect(Display.userName.getAttribute('disabled')).toBe('true'); - }); - - it('Email should be an editable field', () => { - expect(Display.userEmail.getAttribute('disabled')).toBe(null); - }); - - xit('Invalid emails can not be saved', () => { - Display.userEmail.setValue('fakeemail'); - Display.submitButton.click(); - Display.invalidEmailWarning.waitForVisible(constants.wait.normal); - expect(Display.invalidEmailWarning.getText()).toEqual('email must be a valid email'); - Display.cancelButton.click(); - }); - - it('Valid email can be saved', () => { - const validEmail = 'test@gmail.com'; - Display.userEmail.setValue(validEmail); - Display.submitButton.click(); - Display.waitForNotice('Email address updated.'); - expect(getProfile().email).toBe(validEmail); - }); - - it('Change user timezone', () => { - const gmtOffset = '(GMT -05:00) Eastern Time'; - const timeZoneResponse = 'America/New_York'; - expect(Display.timeZoneSelect.isVisible()).toBe(true); - Display.timeZoneSelect.$('..').$('input').setValue(gmtOffset); - Display.selectOptions[0].waitForVisible(constants.wait.normal); - Display.selectOptions[0].click(0); - Display.saveTimeZone.click(); - Display.waitForNotice('Account timezone updated.'); - expect(getProfile().timezone).toBe(timeZoneResponse); - }); + let resetProfileBody; + + beforeAll(() => { + browser.url(constants.routes.profile.view); + const startProfile = getProfile(); + resetProfileBody = { + email: startProfile.email, + timezone: startProfile.timezone + }; + }); + + afterAll(() => { + updateProfile(resetProfileBody); + }); + + it('Should display the update display settings view', () => { + Display.baseElementsDisplay(); + }); + + it('Display name should not be editable', () => { + expect(Display.userName.getAttribute('disabled')).toBe('true'); + }); + + it('Email should be an editable field', () => { + expect(Display.userEmail.getAttribute('disabled')).toBe(null); + }); + + it('Invalid emails can not be saved', () => { + Display.userEmail.setValue('fakeemail'); + Display.submitButton.click(); + Display.invalidEmailWarning.waitForVisible(constants.wait.normal); + expect(Display.invalidEmailWarning.getText()).toEqual( + 'email must be a valid email' + ); + Display.cancelButton.click(); + }); + + it('Valid email can be saved', () => { + const validEmail = 'test@gmail.com'; + Display.userEmail.setValue(validEmail); + Display.submitButton.click(); + Display.waitForNotice('Email address updated.'); + expect(getProfile().email).toBe(validEmail); + }); + + it('Change user timezone', () => { + const gmtOffset = '(GMT -5:00) Eastern Time - New York'; + const timeZoneResponse = 'America/New_York'; + expect(Display.timeZoneSelect.isVisible()).toBe(true); + Display.timeZoneSelect + .$('..') + .$('input') + .setValue(gmtOffset); + Display.selectOptions[0].waitForVisible(constants.wait.normal); + Display.selectOptions[0].click(0); + Display.saveTimeZone.click(); + Display.waitForNotice('Account timezone updated.'); + expect(getProfile().timezone).toBe(timeZoneResponse); + }); }); diff --git a/e2e/specs/stackscripts/stackscript-detail.spec.js b/e2e/specs/stackscripts/stackscript-detail.spec.js index 498f963a617..adcb1e73892 100644 --- a/e2e/specs/stackscripts/stackscript-detail.spec.js +++ b/e2e/specs/stackscripts/stackscript-detail.spec.js @@ -1,7 +1,7 @@ const { constants } = require('../../constants'); import { apiDeleteMyStackScripts, - getDistrobutionLabel, + getDistributionLabel, timestamp, switchTab, } from '../../utils/common'; @@ -21,25 +21,25 @@ describe('StackScript - detail page and drawer suite', () => { }, constants.wait.normal); const titleAndAuthor = $$(`${ListStackScripts.stackScriptTitle.selector} h3`)[0].getText(); const deploys = $$(ListStackScripts.stackScriptDeploys.selector)[0].getText(); - const compatibleDisrobutions = $$(ListStackScripts.stackScriptCompatibleDistrobutions.selector)[0].$$('div').map(distro => distro.getText()); + const compatibleDistributions = $$(ListStackScripts.stackScriptCompatibleDistributions.selector)[0].$$('div').map(distro => distro.getText()); const getTitleAndAuthor = titleAndAuthor.split('/'); const stackScriptDetails = { title: getTitleAndAuthor[1].trim(), author: getTitleAndAuthor[0].trim(), deploys: deploys, - distrobutions: compatibleDisrobutions + distributions: compatibleDistributions } return stackScriptDetails; } - const verifyStackScriptDetailPageOrDrawer = (title,author,deployments,disrobutions,description,code) => { + const verifyStackScriptDetailPageOrDrawer = (title,author,deployments,distributions,description,code) => { expect(StackScriptDetail.stackScriptTitle(title).isVisible()).toBe(true); expect(StackScriptDetail.stackScriptAuthor(author).isVisible()).toBe(true); expect(StackScriptDetail.stackScriptDeployments.getText()).toContain(deployments); - const selectedDistrobutionLabels = getDistrobutionLabel(disrobutions); - const displayedDistrobutionLabels = StackScriptDetail.getStackScriptCompatibleDisrobutions(); - selectedDistrobutionLabels.forEach((distro) => { - expect(displayedDistrobutionLabels.includes(distro)).toBe(true); + const selectedDistributionLabels = getDistributionLabel(distributions); + const displayedDistributionsLabels = StackScriptDetail.getStackScriptCompatibleDistributions(); + selectedDistributionLabels.forEach((distro) => { + expect(displayedDistributionsLabels.includes(distro)).toBe(true); }); if(description){ expect(StackScriptDetail.stackScriptDescription.getText()).toContain(description); @@ -72,7 +72,7 @@ describe('StackScript - detail page and drawer suite', () => { }); it('Verify StackScript details correspond to the row clicked', () => { - verifyStackScriptDetailPageOrDrawer(selectedStackScript.title,selectedStackScript.author,selectedStackScript.deploys,selectedStackScript.distrobutions); + verifyStackScriptDetailPageOrDrawer(selectedStackScript.title,selectedStackScript.author,selectedStackScript.deploys,selectedStackScript.distributions); }); it('Breadcrumb link navigates back to StackScript landing', () => { @@ -160,7 +160,7 @@ describe('StackScript - detail page and drawer suite', () => { }); it('Verify StackScript drawer details correspond to the row clicked', () => { - verifyStackScriptDetailPageOrDrawer(selectedStackScript.title,selectedStackScript.author,selectedStackScript.deploys,selectedStackScript.distrobutions); + verifyStackScriptDetailPageOrDrawer(selectedStackScript.title,selectedStackScript.author,selectedStackScript.deploys,selectedStackScript.distributions); expect(StackScriptDetail.drawerTitle.getText()).toEqual(`${selectedStackScript.author} / ${selectedStackScript.title}`); StackScriptDetail.drawerClose.click(); ConfigureLinode.drawerBase.waitForVisible(constants.wait.normal, true); diff --git a/e2e/utils/common.js b/e2e/utils/common.js index efd5cb5ce54..380d115bf67 100644 --- a/e2e/utils/common.js +++ b/e2e/utils/common.js @@ -232,14 +232,14 @@ export const switchTab = () => { browser.switchTab(newTab); } -export const getDistrobutionLabel = (distrobutionTags) => { +export const getDistributionLabel = (distributionTags) => { const token = readToken(browser.options.testUser); - let distrobutionLabel = []; - distrobutionTags.forEach((distro) => { + let distributionLabel = []; + distributionTags.forEach((distro) => { const distroDetails = browser.getLinodeImage(token,distro.trim()); - distrobutionLabel.push(distroDetails.label); + distributionLabel.push(distroDetails.label); }); - return distrobutionLabel; + return distributionLabel; } export const getLocalStorageValue = (key) => { diff --git a/src/components/ActionMenu/ActionMenu.tsx b/src/components/ActionMenu/ActionMenu.tsx index 0ba9630b422..26dfe968a82 100644 --- a/src/components/ActionMenu/ActionMenu.tsx +++ b/src/components/ActionMenu/ActionMenu.tsx @@ -136,6 +136,12 @@ export class ActionMenu extends React.Component { transformOrigin={{ vertical: 'top', horizontal: 'right' }} open={Boolean(anchorEl)} onClose={this.handleClose} + BackdropProps={{ + style: { + backgroundColor: 'transparent' + }, + 'data-qa-backdrop': true + }} > {(actions as Action[]).map((a, idx) => ( diff --git a/src/components/PrimaryNav/PrimaryNav.tsx b/src/components/PrimaryNav/PrimaryNav.tsx index 5527161f86a..0d3ce6552bf 100644 --- a/src/components/PrimaryNav/PrimaryNav.tsx +++ b/src/components/PrimaryNav/PrimaryNav.tsx @@ -504,7 +504,10 @@ export class PrimaryNav extends React.Component { anchorOrigin={{ vertical: 'top', horizontal: 'center' }} transformOrigin={{ vertical: 'bottom', horizontal: 'center' }} className={classes.menu} - BackdropProps={{ className: classes.settingsBackdrop }} + BackdropProps={{ + className: classes.settingsBackdrop, + 'data-qa-backdrop': true + }} > diff --git a/src/components/TagsCell/TagsCell.tsx b/src/components/TagsCell/TagsCell.tsx index c2b53db6a82..978ce0fc1ea 100644 --- a/src/components/TagsCell/TagsCell.tsx +++ b/src/components/TagsCell/TagsCell.tsx @@ -50,7 +50,7 @@ const LinodeRowTagCell: React.StatelessComponent = props => { leaveDelay={50} interactive={true} > -
+
{tags.length} diff --git a/src/features/linodes/LinodesDetail/LinodeRebuild/RebuildDialog.tsx b/src/features/linodes/LinodesDetail/LinodeRebuild/RebuildDialog.tsx index b9670aed27a..050415fc056 100644 --- a/src/features/linodes/LinodesDetail/LinodeRebuild/RebuildDialog.tsx +++ b/src/features/linodes/LinodesDetail/LinodeRebuild/RebuildDialog.tsx @@ -25,6 +25,7 @@ export const RebuildDialog: React.StatelessComponent< type="secondary" destructive onClick={handleSubmit} + data-qa-submit-rebuild loading={isLoading} > Rebuild