Skip to content
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
16 changes: 13 additions & 3 deletions web/packages/design/src/Alert/Alert.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,23 @@ const kind = props => {
case 'outline-danger':
return {
background: fade(theme.colors.error.main, 0.1),
border: `${theme.radii[1]}px solid ${theme.colors.error.main}`,
border: `${theme.borders[2]} ${theme.colors.error.main}`,
borderRadius: `${theme.radii[3]}px`,
boxShadow: 'none',
justifyContent: 'normal',
};
case 'outline-info':
return {
background: fade(theme.colors.link, 0.1),
border: `${theme.radii[1]}px solid ${theme.colors.link}`,
background: fade(theme.colors.accent.main, 0.1),
border: `${theme.borders[2]} ${theme.colors.accent.main}`,
borderRadius: `${theme.radii[3]}px`,
boxShadow: 'none',
justifyContent: 'normal',
};
case 'outline-warn':
return {
background: fade(theme.colors.warning.main, 0.1),
border: `${theme.borders[2]} ${theme.colors.warning.main}`,
borderRadius: `${theme.radii[3]}px`,
boxShadow: 'none',
justifyContent: 'normal',
Expand Down Expand Up @@ -100,6 +108,7 @@ Alert.propTypes = {
'success',
'outline-danger',
'outline-info',
'outline-warn',
]),
...color.propTypes,
...space.propTypes,
Expand All @@ -121,3 +130,4 @@ export const OutlineDanger = props => (
<Alert kind="outline-danger" {...props} />
);
export const OutlineInfo = props => <Alert kind="outline-info" {...props} />;
export const OutlineWarn = props => <Alert kind="outline-warn" {...props} />;
2 changes: 2 additions & 0 deletions web/packages/design/src/Alert/Alert.story.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,7 @@ export const Alerts = () => (
<Alert kind="info">Some informational message</Alert>
<Alert kind="success">This is success</Alert>
<Alert kind="outline-info">Text align it yourself</Alert>
<Alert kind="outline-warn">Text align it yourself</Alert>
<Alert kind="outline-danger">Text align it yourself</Alert>
</Box>
);
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import {
createDiscoveryConfig,
} from 'teleport/services/discovery';
import useTeleport from 'teleport/useTeleport';
import { splitAwsIamArn } from 'teleport/services/integrations/aws';

import {
AutoEnrollDialog,
Expand Down Expand Up @@ -221,13 +222,11 @@ export function EnrollRdsDatabase() {
if (!requiredVpcsAndSubnets) {
try {
const { spec, name: integrationName } = agentMeta.awsIntegration;
const accountId = spec.roleArn
.split('arn:aws:iam::')[1]
.substring(0, 12);
const { awsAccountId } = splitAwsIamArn(spec.roleArn);
requiredVpcsAndSubnets =
await integrationService.fetchAwsRdsRequiredVpcs(integrationName, {
region: tableData.currRegion,
accountId,
accountId: awsAccountId,
});

setRequiredVpcs(requiredVpcsAndSubnets);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { render, screen, fireEvent } from 'design/utils/testing';
import { render, screen, fireEvent, waitFor } from 'design/utils/testing';
import userEvent from '@testing-library/user-event';

import {
Integration,
Expand All @@ -25,7 +26,7 @@ import {

import { EditAwsOidcIntegrationDialog } from './EditAwsOidcIntegrationDialog';

test('edit without s3 fields', async () => {
test('user acknowledging script was ran when s3 bucket fields are edited', async () => {
render(
<EditAwsOidcIntegrationDialog
close={() => null}
Expand All @@ -36,7 +37,7 @@ test('edit without s3 fields', async () => {
name: 'some-integration-name',
spec: {
roleArn: 'arn:aws:iam::123456789012:role/johndoe',
issuerS3Bucket: '',
issuerS3Bucket: 'test-value',
issuerS3Prefix: '',
},
statusCode: IntegrationStatusCode.Running,
Expand All @@ -45,18 +46,29 @@ test('edit without s3 fields', async () => {
);

// Initial state.
expect(screen.getByText(/required/i)).toBeInTheDocument();
expect(screen.queryByTestId('scriptbox')).not.toBeInTheDocument();
expect(screen.queryByTestId('checkbox')).not.toBeInTheDocument();
expect(
screen.queryByRole('button', { name: /generate command/i })
).not.toBeInTheDocument();
expect(screen.getByRole('button', { name: /save/i })).toBeDisabled();

// Click on generate command:
// Fill in the s3 prefix field.
fireEvent.change(screen.getByPlaceholderText(/prefix/i), {
target: { value: 'test-value' },
});
await waitFor(() =>
expect(
screen.getByRole('button', { name: /generate command/i })
).toBeEnabled()
);
// When clicking on generate command:
// - script rendered
// - checkbox to confirm user has ran command
// - edit button replaces generate command button
// - save button still disabled
fireEvent.click(screen.getByRole('button', { name: /generate command/i }));
screen.getByRole('button', { name: /edit/i });
userEvent.click(screen.getByRole('button', { name: /generate command/i }));
await screen.findByRole('button', { name: /edit/i });
expect(screen.getByRole('button', { name: /save/i })).toBeDisabled();
expect(
screen.queryByRole('button', { name: /generate command/i })
Expand All @@ -65,54 +77,153 @@ test('edit without s3 fields', async () => {
expect(screen.getByTestId('scriptbox')).toBeInTheDocument();

// Click on checkbox should enable save button and disable edit button.
fireEvent.click(screen.getByRole('checkbox'));
expect(screen.getByRole('button', { name: /save/i })).toBeEnabled();
userEvent.click(screen.getByRole('checkbox'));
await waitFor(() =>
expect(screen.getByRole('button', { name: /save/i })).toBeEnabled()
);
expect(screen.getByRole('button', { name: /edit/i })).toBeDisabled();

// Unchecking the checkbox should disable save button.
fireEvent.click(screen.getByRole('checkbox'));
expect(screen.getByRole('button', { name: /save/i })).toBeDisabled();
userEvent.click(screen.getByRole('checkbox'));
await waitFor(() =>
expect(screen.getByRole('button', { name: /save/i })).toBeDisabled()
);

// Click on edit, should replace it with generate command
fireEvent.click(screen.getByRole('button', { name: /edit/i }));
expect(
screen.getByRole('button', { name: /generate command/i })
).toBeEnabled();
userEvent.click(screen.getByRole('button', { name: /edit/i }));
await waitFor(() =>
expect(
screen.getByRole('button', { name: /generate command/i })
).toBeEnabled()
);
});

test('edit with s3 fields', async () => {
test('render warning on save when leaving s3 fields empty', async () => {
const edit = jest.fn(() => Promise.resolve());
render(
<EditAwsOidcIntegrationDialog
close={() => null}
edit={() => null}
integration={integration}
edit={edit}
integration={{
resourceType: 'integration',
kind: IntegrationKind.AwsOidc,
name: 'some-integration-name',
spec: {
roleArn: 'arn:aws:iam::123456789012:role/johndoe',
issuerS3Bucket: '',
issuerS3Prefix: '',
},
statusCode: IntegrationStatusCode.Running,
}}
/>
);

// Initial state.
expect(screen.queryByText(/required/i)).not.toBeInTheDocument();
expect(screen.queryByTestId('scriptbox')).not.toBeInTheDocument();
expect(screen.queryByTestId('checkbox')).not.toBeInTheDocument();
expect(screen.getByRole('button', { name: /save/i })).toBeDisabled();
expect(
screen.queryByRole('button', { name: /generate command/i })
).not.toBeInTheDocument();

// Changing role arn should not render generate command.
// Enable the generate command button by changing a field.
fireEvent.change(screen.getByPlaceholderText(/arn:aws:iam:/i), {
target: { value: 'something else' },
target: { value: 'arn:aws:iam::123456789012:role/someonelse' },
});
expect(screen.getByRole('button', { name: /save/i })).toBeEnabled();
await waitFor(() =>
expect(
screen.getByRole('button', { name: /generate command/i })
).toBeEnabled()
);

expect(screen.queryByTestId('checkbox')).not.toBeInTheDocument();
expect(screen.getByRole('button', { name: /save/i })).toBeDisabled();

userEvent.click(screen.getByRole('button', { name: /generate command/i }));
await screen.findByRole('button', { name: /edit/i });
expect(screen.getByRole('button', { name: /save/i })).toBeDisabled();

userEvent.click(screen.getByTestId('checkbox'));
await waitFor(() =>
expect(screen.getByRole('button', { name: /save/i })).toBeEnabled()
);

// Clicking on save without defining s3 fields, should render
// a warning.
userEvent.click(screen.getByRole('button', { name: /save/i }));
await screen.findByText(/recommended to use an S3 bucket/i);
expect(edit).not.toHaveBeenCalled();

// Canceling and saving should re-render the warning.
userEvent.click(screen.getByRole('button', { name: /cancel/i }));
await screen.findByRole('button', { name: /save/i });

userEvent.click(screen.getByRole('button', { name: /save/i }));
await screen.findByText(/recommended to use an S3 bucket/i);

userEvent.click(screen.getByRole('button', { name: /continue/i }));
await waitFor(() => expect(edit).toHaveBeenCalledTimes(1));
});

test('render warning on save when deleting existing s3 fields', async () => {
const edit = jest.fn(() => Promise.resolve());
render(
<EditAwsOidcIntegrationDialog
close={() => null}
edit={edit}
integration={{
resourceType: 'integration',
kind: IntegrationKind.AwsOidc,
name: 'some-integration-name',
spec: {
roleArn: 'arn:aws:iam::123456789012:role/johndoe',
issuerS3Bucket: 'delete-me',
issuerS3Prefix: 'delete-me',
},
statusCode: IntegrationStatusCode.Running,
}}
/>
);

expect(
screen.queryByRole('button', { name: /generate command/i })
).not.toBeInTheDocument();

// Changing the s3 fields should render generate command.
// Delete the s3 fields.
fireEvent.change(screen.getByPlaceholderText(/bucket/i), {
target: { value: 's3-bucket-something' },
target: { value: '' },
});
fireEvent.click(screen.getByRole('button', { name: /generate command/i }));
fireEvent.change(screen.getByPlaceholderText(/prefix/i), {
target: { value: '' },
});
await waitFor(() =>
expect(
screen.getByRole('button', { name: /generate command/i })
).toBeEnabled()
);

expect(screen.queryByTestId('checkbox')).not.toBeInTheDocument();
expect(screen.getByRole('button', { name: /save/i })).toBeDisabled();

userEvent.click(screen.getByRole('button', { name: /generate command/i }));
await screen.findByRole('button', { name: /edit/i });
expect(screen.getByRole('button', { name: /save/i })).toBeDisabled();

userEvent.click(screen.getByTestId('checkbox'));
await waitFor(() =>
expect(screen.getByRole('button', { name: /save/i })).toBeEnabled()
);

// Test for warning render.
userEvent.click(screen.getByRole('button', { name: /save/i }));
await screen.findByText(/recommended to use an S3 bucket/i);
expect(edit).not.toHaveBeenCalled();
expect(
screen.getByText(/recommended to use an S3 bucket/i)
).toBeInTheDocument();

userEvent.click(screen.getByRole('button', { name: /continue/i }));
await waitFor(() => expect(edit).toHaveBeenCalledTimes(1));
});

test('edit invalid fields', async () => {
Expand All @@ -131,22 +242,18 @@ test('edit invalid fields', async () => {
target: { value: 'role something else' },
});

fireEvent.click(screen.getByRole('button', { name: /save/i }));
expect(screen.getByText(/invalid role ARN format/i)).toBeInTheDocument();
await waitFor(() =>
expect(
screen.getByRole('button', { name: /generate command/i })
).toBeEnabled()
);

// invalid s3 fields
fireEvent.change(screen.getByPlaceholderText(/bucket/i), {
target: { value: '' },
});
fireEvent.change(screen.getByPlaceholderText(/prefix/i), {
target: { value: '' },
});
fireEvent.click(screen.getByRole('button', { name: /generate command/i }));
expect(screen.queryAllByText(/required/i)).toHaveLength(2);
userEvent.click(screen.getByRole('button', { name: /generate command/i }));
await screen.findByText(/invalid role ARN format/i);
});

test('edit submit', async () => {
const mockEditFn = jest.fn();
test('edit submit called with proper fields', async () => {
const mockEditFn = jest.fn(() => Promise.resolve());
render(
<EditAwsOidcIntegrationDialog
close={() => null}
Expand All @@ -170,9 +277,21 @@ test('edit submit', async () => {
target: { value: 'other-prefix' },
});

fireEvent.click(screen.getByRole('button', { name: /generate command/i }));
fireEvent.click(screen.getByRole('checkbox'));
fireEvent.click(screen.getByRole('button', { name: /save/i }));
await waitFor(() =>
expect(
screen.getByRole('button', { name: /generate command/i })
).toBeEnabled()
);

userEvent.click(screen.getByRole('button', { name: /generate command/i }));
await screen.findByRole('button', { name: /edit/i });

userEvent.click(screen.getByTestId('checkbox'));
await waitFor(() =>
expect(screen.getByRole('button', { name: /save/i })).toBeEnabled()
);
userEvent.click(screen.getByRole('button', { name: /save/i }));
await waitFor(() => expect(mockEditFn).toHaveBeenCalledTimes(1));

expect(mockEditFn).toHaveBeenCalledWith({
roleArn: 'arn:aws:iam::123456789011:role/other',
Expand Down
Loading