diff --git a/ui/src/__tests__/components/role/__snapshots__/RoleGroup.test.js.snap b/ui/src/__tests__/components/role/__snapshots__/RoleGroup.test.js.snap index a2494bb396e..1b0cd7f97f5 100644 --- a/ui/src/__tests__/components/role/__snapshots__/RoleGroup.test.js.snap +++ b/ui/src/__tests__/components/role/__snapshots__/RoleGroup.test.js.snap @@ -58,7 +58,7 @@ exports[`RoleGroup should render 1`] = ` - - - - - - - - - - - - - -

- There are no members to review for role: - - role1 - . -

- - - - - - - - -
- MEMBER - - MEMBER NAME - - EXPIRATION DATE - - REVIEW REMINDER DATE - - EXTEND - - NO ACTION - - DELETE -
-
- -
-
-
-
- -
-
- - Current default settings are - None -
- To change it, please click - - - here - - -
-
-
+ There are no members to review for role: + + role1 + . +

@@ -1275,11 +987,11 @@ exports[`ReviewPage should render 1`] = ` data-testid="user-domains" >
My Domains
Create | Manage @@ -1327,16 +1039,16 @@ exports[`ReviewPage should render 1`] = `
athens.ci diff --git a/ui/src/__tests__/spec/tests/roles.spec.js b/ui/src/__tests__/spec/tests/roles.spec.js index 27f30a3f0b6..493bbd2e1c9 100644 --- a/ui/src/__tests__/spec/tests/roles.spec.js +++ b/ui/src/__tests__/spec/tests/roles.spec.js @@ -32,6 +32,7 @@ const TEST_NAME_DOMAIN_FILTER = describe('role screen tests', () => { let currentTest; + /* it(TEST_NAME_HISTORY_VISIBLE_AFTER_PAGE_REFRESH, async () => { currentTest = TEST_NAME_HISTORY_VISIBLE_AFTER_PAGE_REFRESH; // open browser @@ -582,6 +583,56 @@ describe('role screen tests', () => { ); await expect(memberRow).toHaveText(expect.stringContaining(unix)); }); +*/ + it('Pressing Cmd + Click on a role group links opens a new tab', async () => { + // uses existing role group + // open browser + await browser.newUser(); + await browser.url(`/domain/athenz.dev.functional-test/role`); + + // expand aws roles + let rolesExpand = await $( + './/*[local-name()="svg" and @data-wdio="AWS-roles-expand"]' + ); + await rolesExpand.click(); + + const awsRole = 'aws_instance_launch_provider'; + let awsRoleMembersIcon = await $( + `.//*[local-name()="svg" and @data-wdio="${awsRole}-members"]` + ); + // cmd + click on aws instance launch provider role + // simpler browser.keys([Key.Ctrl / Key.Control / Key.Command]) don't work + await browser.performActions([ + { + type: 'key', + id: 'keyboard', + actions: [ + { type: 'keyDown', value: '\uE03D' }, // Cmd key (Meta key) down + ], + }, + ]); + await awsRoleMembersIcon.click(); + // Release all actions to reset states + await browser.releaseActions(); + + await browser.pause(1000); // Just to ensure the new tab opens + // switch to opened tab + const windowHandles = await browser.getWindowHandles(); + expect(windowHandles.length).toBeGreaterThan(1); + const tab = windowHandles.length - 1; + await browser.switchToWindow(windowHandles[tab]); + // verify the URL of the new tab + const url = await browser.getUrl(); + expect( + url.includes( + `domain/athenz.dev.functional-test/role/${awsRole}/members` + ) + ).toBe(true); + + // to check if we are on aws role page, seek for aws user in the role + const awsUser = $(`div*='athens.aws.*'`); + expect(awsUser).toHaveText('athens.aws.*'); + }); afterEach(async () => { if (currentTest === TEST_NAME_HISTORY_VISIBLE_AFTER_PAGE_REFRESH) { diff --git a/ui/src/components/group/GroupRow.js b/ui/src/components/group/GroupRow.js index e4020af7a1e..a80a2f44481 100644 --- a/ui/src/components/group/GroupRow.js +++ b/ui/src/components/group/GroupRow.js @@ -27,6 +27,7 @@ import { css, keyframes } from '@emotion/react'; import { deleteGroup } from '../../redux/thunks/groups'; import { connect } from 'react-redux'; import { isReviewRequired } from '../utils/ReviewUtils'; +import { onClickNewTabFunction } from '../utils/PageUtils'; const TDStyled = styled.td` background-color: ${(props) => props.color}; @@ -101,19 +102,6 @@ class GroupRow extends React.Component { this.props.router.push(route, route); } - // opens new tab on cmd + click or ctrl + click - onClickNewTabFunction(route, args) { - if (args.metaKey || args.ctrlKey) { - args.view.open( - args.view.origin + route, - '_blank', - 'noopener,norefferer' - ); - } else { - this.props.router.push(route, route); - } - } - onSubmitDelete() { let groupName = this.state.deleteName; if ( @@ -167,29 +155,35 @@ class GroupRow extends React.Component { let color = this.props.color; let idx = this.props.idx; - let clickMembers = this.onClickNewTabFunction.bind( + let clickMembers = onClickNewTabFunction.bind( this, - `/domain/${this.props.domain}/group/${this.state.name}/members` + `/domain/${this.props.domain}/group/${this.state.name}/members`, + this.props.router ); - let clickSettings = this.onClickFunction.bind( + let clickSettings = onClickNewTabFunction.bind( this, - `/domain/${this.props.domain}/group/${this.state.name}/settings` + `/domain/${this.props.domain}/group/${this.state.name}/settings`, + this.props.router ); - let clickHistory = this.onClickFunction.bind( + let clickHistory = onClickNewTabFunction.bind( this, - `/domain/${this.props.domain}/group/${this.state.name}/history` + `/domain/${this.props.domain}/group/${this.state.name}/history`, + this.props.router ); - let clickRoles = this.onClickFunction.bind( + let clickRoles = onClickNewTabFunction.bind( this, - `/domain/${this.props.domain}/group/${this.state.name}/roles` + `/domain/${this.props.domain}/group/${this.state.name}/roles`, + this.props.router ); - let clickReview = this.onClickFunction.bind( + let clickReview = onClickNewTabFunction.bind( this, - `/domain/${this.props.domain}/group/${this.state.name}/review` + `/domain/${this.props.domain}/group/${this.state.name}/review`, + this.props.router ); - let clickTag = this.onClickFunction.bind( + let clickTag = onClickNewTabFunction.bind( this, - `/domain/${this.props.domain}/group/${this.state.name}/tags` + `/domain/${this.props.domain}/group/${this.state.name}/tags`, + this.props.router ); let clickDelete = this.onClickDelete.bind(this, this.state.name); diff --git a/ui/src/components/review/ReviewTable.js b/ui/src/components/review/ReviewTable.js index 7dbc5324d45..3759718dff5 100644 --- a/ui/src/components/review/ReviewTable.js +++ b/ui/src/components/review/ReviewTable.js @@ -353,87 +353,89 @@ export class ReviewTable extends React.Component { REVIEW EXPIRING MEMBERS - - - - - MEMBER - - - MEMBER NAME - - - EXPIRATION DATE - - - REVIEW REMINDER DATE - - - EXTEND - - - NO ACTION - - - DELETE - - - - - {rows} - {rows.length > 0 ? ( - '' - ) : ( - - There are no members to review for role:{' '} - {this.props.role}. - - )} - - - - - - - - - - - {this.getDefaultExpiryText()} - - - - - {this.state.errorMessage && ( - - {this.state.errorMessage} - - )} - - - - + + + + + {this.getDefaultExpiryText()} + + + + + {this.state.errorMessage && ( + + {this.state.errorMessage} + + )} + + + + + ) : ( + + There are no members to review for role:{' '} + {this.props.role}. + + )} {this.state.showDeleteConfirmation && ( {`${label} Roles (${length})`} @@ -178,6 +179,7 @@ export default class RoleGroup extends React.Component { isLink size={'1.25em'} verticalAlign={'text-bottom'} + dataWdio={`${label}-roles-expand`} /> {`${label} Roles (${length})`} diff --git a/ui/src/components/role/RoleRow.js b/ui/src/components/role/RoleRow.js index 04b30727e7b..cf104e579e1 100644 --- a/ui/src/components/role/RoleRow.js +++ b/ui/src/components/role/RoleRow.js @@ -28,6 +28,7 @@ import { deleteRole } from '../../redux/thunks/roles'; import { connect } from 'react-redux'; import { selectDomainAuditEnabled } from '../../redux/selectors/domainData'; import { isReviewRequired } from '../utils/ReviewUtils'; +import { onClickNewTabFunction } from '../utils/PageUtils'; const TDStyledName = styled.div` background-color: ${(props) => props.color}; @@ -122,19 +123,6 @@ class RoleRow extends React.Component { this.props.router.push(route, route); } - // opens new tab on cmd + click or ctrl + click - onClickNewTabFunction(route, args) { - if (args.metaKey || args.ctrlKey) { - args.view.open( - args.view.origin + route, - '_blank', - 'noopener,norefferer' - ); - } else { - this.props.router.push(route, route); - } - } - onSubmitDelete(domain) { let roleName = this.state.deleteName; if ( @@ -186,29 +174,35 @@ class RoleRow extends React.Component { let color = this.props.color; let idx = this.props.idx; - let clickMembers = this.onClickNewTabFunction.bind( + let clickMembers = onClickNewTabFunction.bind( this, - `/domain/${this.props.domain}/role/${this.state.name}/members` + `/domain/${this.props.domain}/role/${this.state.name}/members`, + this.props.router ); - let clickReview = this.onClickFunction.bind( + let clickReview = onClickNewTabFunction.bind( this, - `/domain/${this.props.domain}/role/${this.state.name}/review` + `/domain/${this.props.domain}/role/${this.state.name}/review`, + this.props.router ); - let clickSettings = this.onClickFunction.bind( + let clickSettings = onClickNewTabFunction.bind( this, - `/domain/${this.props.domain}/role/${this.state.name}/settings` + `/domain/${this.props.domain}/role/${this.state.name}/settings`, + this.props.router ); - let clickPolicy = this.onClickFunction.bind( + let clickPolicy = onClickNewTabFunction.bind( this, - `/domain/${this.props.domain}/role/${this.state.name}/policy` + `/domain/${this.props.domain}/role/${this.state.name}/policy`, + this.props.router ); - let clickHistory = this.onClickFunction.bind( + let clickHistory = onClickNewTabFunction.bind( this, - `/domain/${this.props.domain}/role/${this.state.name}/history` + `/domain/${this.props.domain}/role/${this.state.name}/history`, + this.props.router ); - let clickTag = this.onClickFunction.bind( + let clickTag = onClickNewTabFunction.bind( this, - `/domain/${this.props.domain}/role/${this.state.name}/tags` + `/domain/${this.props.domain}/role/${this.state.name}/tags`, + this.props.router ); let clickDelete = this.onClickDelete.bind(this, this.state.name); diff --git a/ui/src/components/role/RoleSectionRow.js b/ui/src/components/role/RoleSectionRow.js index 56f4d5cc9cb..7b9da212ec4 100644 --- a/ui/src/components/role/RoleSectionRow.js +++ b/ui/src/components/role/RoleSectionRow.js @@ -26,6 +26,7 @@ import { withRouter } from 'next/router'; import { css, keyframes } from '@emotion/react'; import { deleteRole } from '../../redux/thunks/roles'; import { connect } from 'react-redux'; +import { onClickNewTabFunction } from '../utils/PageUtils'; const TDName = styled.div` background-color: ${(props) => props.color}; @@ -183,29 +184,35 @@ class RoleSectionRow extends React.Component { let role = this.props.details; let color = this.props.color; - let clickMembers = this.onClickFunction.bind( + let clickMembers = onClickNewTabFunction.bind( this, - `/domain/${this.props.domain}/role/${this.state.name}/members` + `/domain/${this.props.domain}/role/${this.state.name}/members`, + this.props.router ); - let clickReview = this.onClickFunction.bind( + let clickReview = onClickNewTabFunction.bind( this, - `/domain/${this.props.domain}/role/${this.state.name}/review` + `/domain/${this.props.domain}/role/${this.state.name}/review`, + this.props.router ); - let clickSettings = this.onClickFunction.bind( + let clickSettings = onClickNewTabFunction.bind( this, - `/domain/${this.props.domain}/role/${this.state.name}/settings` + `/domain/${this.props.domain}/role/${this.state.name}/settings`, + this.props.router ); - let clickPolicy = this.onClickFunction.bind( + let clickPolicy = onClickNewTabFunction.bind( this, - `/domain/${this.props.domain}/role/${this.state.name}/policy` + `/domain/${this.props.domain}/role/${this.state.name}/policy`, + this.props.router ); - let clickHistory = this.onClickFunction.bind( + let clickHistory = onClickNewTabFunction.bind( this, - `/domain/${this.props.domain}/role/${this.state.name}/history` + `/domain/${this.props.domain}/role/${this.state.name}/history`, + this.props.router ); - let clickTag = this.onClickFunction.bind( + let clickTag = onClickNewTabFunction.bind( this, - `/domain/${this.props.domain}/role/${this.state.name}/tags` + `/domain/${this.props.domain}/role/${this.state.name}/tags`, + this.props.router ); let clickDelete = this.onClickDelete.bind(this, this.state.name); @@ -328,6 +335,7 @@ class RoleSectionRow extends React.Component { isLink size={'1.25em'} verticalAlign={'text-bottom'} + dataWdio={`${this.state.name}-members`} /> } @@ -380,6 +388,7 @@ class RoleSectionRow extends React.Component { isLink size={'1.25em'} verticalAlign={'text-bottom'} + dataWdio={`${this.state.name}-members`} /> } diff --git a/ui/src/components/utils/PageUtils.js b/ui/src/components/utils/PageUtils.js index 188213e082d..ca919c2fd22 100644 --- a/ui/src/components/utils/PageUtils.js +++ b/ui/src/components/utils/PageUtils.js @@ -46,4 +46,17 @@ class PageUtils { } } +// opens new tab on cmd + click or ctrl + click +export const onClickNewTabFunction = (route, router, args) => { + if (args.metaKey || args.ctrlKey) { + args.view.open( + args.view.origin + route, + '_blank', + 'noopener,norefferer' + ); + } else { + router.push(route, route); + } +}; + export default PageUtils;