Skip to content

Commit c780d67

Browse files
author
aws-amplify-bot
committed
refactor: unit tests
1 parent b4cc448 commit c780d67

9 files changed

Lines changed: 106 additions & 109 deletions

File tree

packages/amplify-provider-awscloudformation/src/__tests__/amplify-service-manager.test.ts

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
1-
import { Amplify } from 'aws-sdk';
21
import { stateManager } from '@aws-amplify/amplify-cli-core';
32
import { getConfiguredAmplifyClient } from '../aws-utils/aws-amplify';
43
import { checkAmplifyServiceIAMPermission } from '../amplify-service-permission-check';
54
import { init } from '../amplify-service-manager';
5+
import { mockClient } from 'aws-sdk-client-mock';
6+
import 'aws-sdk-client-mock-jest';
7+
import { AmplifyClient, CreateAppCommand } from '@aws-sdk/client-amplify';
68

79
jest.mock('../aws-utils/aws-amplify');
810
jest.mock('../amplify-service-permission-check');
911

10-
const amplifyClientStub = {
11-
createApp: jest.fn().mockReturnValue({
12-
promise: jest.fn().mockRejectedValue({
13-
code: 'LimitExceededException',
14-
}),
15-
}),
16-
} as unknown as Amplify;
12+
const mockAmplifyClient = mockClient(AmplifyClient);
1713
const getConfiguredAmplifyClientMock = getConfiguredAmplifyClient as jest.MockedFunction<typeof getConfiguredAmplifyClient>;
18-
getConfiguredAmplifyClientMock.mockResolvedValue(amplifyClientStub);
1914

2015
const checkAmplifyServiceIAMPermissionMock = checkAmplifyServiceIAMPermission as jest.MockedFunction<
2116
typeof checkAmplifyServiceIAMPermission
@@ -25,7 +20,16 @@ checkAmplifyServiceIAMPermissionMock.mockResolvedValue(true);
2520
jest.spyOn(stateManager, 'teamProviderInfoExists').mockReturnValue(false);
2621

2722
describe('init', () => {
23+
beforeEach(() => {
24+
getConfiguredAmplifyClientMock.mockClear();
25+
mockAmplifyClient.reset();
26+
});
2827
it('throws ProjectInitError if Amplify app limit has been reached', async () => {
28+
mockAmplifyClient.on(CreateAppCommand).rejectsOnce({
29+
name: 'LimitExceededException',
30+
});
31+
getConfiguredAmplifyClientMock.mockResolvedValue(mockAmplifyClient as unknown as AmplifyClient);
32+
2933
const amplifyServiceParamsStub = {
3034
context: {},
3135
awsConfigInfo: {},
@@ -39,16 +43,11 @@ describe('init', () => {
3943
});
4044

4145
it('throws Configutation error if config level is general and soorcing wrong credentials', async () => {
42-
const amplifyClientGeneralConfigStub = {
43-
createApp: jest.fn().mockReturnValue({
44-
promise: jest.fn().mockRejectedValue({
45-
code: 'ConfigError',
46-
message: 'Missing Region in Config',
47-
}),
48-
}),
49-
} as unknown as Amplify;
50-
getConfiguredAmplifyClientMock.mockClear();
51-
getConfiguredAmplifyClientMock.mockResolvedValue(amplifyClientGeneralConfigStub);
46+
mockAmplifyClient.on(CreateAppCommand).rejectsOnce({
47+
name: 'ConfigError',
48+
message: 'Missing Region in Config',
49+
});
50+
getConfiguredAmplifyClientMock.mockResolvedValue(mockAmplifyClient as unknown as AmplifyClient);
5251

5352
const amplifyServiceParamsStub = {
5453
context: {

packages/amplify-provider-awscloudformation/src/__tests__/aws-utils/cloudformation-error-serializer.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { ResourceStatus } from '@aws-sdk/client-cloudformation';
12
import {
23
deserializeErrorMessages,
34
CFNErrorMessages,
@@ -11,7 +12,7 @@ const eventsWithFailure = [
1112
PhysicalResourceId: 'testStackId1',
1213
LogicalResourceId: 'testLogicalResourceId1',
1314
ResourceType: 'AWS::IAM::Role',
14-
ResourceStatus: 'CREATE_FAILED',
15+
ResourceStatus: ResourceStatus.CREATE_FAILED,
1516
ResourceStatusReason: 'Some valid reason 1',
1617
// below properties are useless since we don't use them in the code
1718
StackId: 'testStackId1',
@@ -23,7 +24,7 @@ const eventsWithFailure = [
2324
PhysicalResourceId: 'testStackId2',
2425
LogicalResourceId: 'testLogicalResourceId2',
2526
ResourceType: 'AWS::CloudFormation::Stack',
26-
ResourceStatus: 'UPDATE_FAILED',
27+
ResourceStatus: ResourceStatus.UPDATE_FAILED,
2728
ResourceStatusReason: 'Some valid reason 2',
2829
// below properties are useless since we don't use them in the code
2930
StackId: 'testStackId2',

packages/amplify-provider-awscloudformation/src/__tests__/display-helpful-urls.test.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { ApiCategoryFacade, BannerMessage, stateManager } from '@aws-amplify/amplify-cli-core';
2-
import { AWSError } from 'aws-sdk';
32
import { printer } from '@aws-amplify/amplify-prompts';
43
import { SNS } from '../aws-utils/aws-sns';
54
import { showGraphQLTransformerVersion, showSMSSandboxWarning } from '../display-helpful-urls';
5+
import { AwsError } from 'aws-sdk-client-mock';
66

77
jest.mock('../aws-utils/aws-sns');
88
jest.mock('@aws-amplify/amplify-cli-core');
@@ -77,8 +77,8 @@ describe('showSMSSandBoxWarning', () => {
7777

7878
describe('when IAM user is missing sandbox permission', () => {
7979
beforeEach(() => {
80-
const authError = new Error() as AWSError;
81-
authError.code = 'AuthorizationError';
80+
const authError = new Error() as AwsError;
81+
authError.name = 'AuthorizationError';
8282
mockedSNSClientInstance.isInSandboxMode.mockRejectedValue(authError);
8383
});
8484
it('should not show any warning if there is no message associated', async () => {
@@ -110,8 +110,8 @@ describe('showSMSSandBoxWarning', () => {
110110

111111
describe('it should not show any warning message when the SNS API is not deployed', () => {
112112
beforeEach(() => {
113-
const resourceNotFoundError = new Error() as AWSError;
114-
resourceNotFoundError.code = 'ResourceNotFound';
113+
const resourceNotFoundError = new Error() as AwsError;
114+
resourceNotFoundError.name = 'ResourceNotFound';
115115
mockedSNSClientInstance.isInSandboxMode.mockRejectedValue(resourceNotFoundError);
116116
});
117117
it('should not print error', async () => {
@@ -127,8 +127,8 @@ describe('showSMSSandBoxWarning', () => {
127127

128128
describe('it should not show any warning message when there is a network error', () => {
129129
beforeEach(() => {
130-
const networkError = new Error() as AWSError;
131-
networkError.code = 'UnknownEndpoint';
130+
const networkError = new Error() as AwsError;
131+
networkError.name = 'UnknownEndpoint';
132132
mockedSNSClientInstance.isInSandboxMode.mockRejectedValue(networkError);
133133
});
134134

packages/amplify-provider-awscloudformation/src/__tests__/initialize-env.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ describe('initialize environment', () => {
1818
},
1919
} as unknown as $TSContext;
2020
it('throws AmplifyError if the deployment bucket does not exist', async () => {
21-
downloadZipMock.mockRejectedValueOnce({ code: 'NoSuchBucket' });
21+
downloadZipMock.mockRejectedValueOnce({ name: 'NoSuchBucket' });
2222
const actual = await expect(run(contextStub, {})).rejects;
2323
await actual.toBeInstanceOf(AmplifyException);
2424
await actual.toMatchInlineSnapshot(

packages/amplify-provider-awscloudformation/src/__tests__/iterative-deployment/stack-event-monitor.test.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,26 @@
1-
import type { CloudFormation } from 'aws-sdk';
21
import { StackEventMonitor } from '../../iterative-deployment/stack-event-monitor';
2+
import { mockClient } from 'aws-sdk-client-mock';
3+
import 'aws-sdk-client-mock-jest';
4+
import { CloudFormationClient, DescribeStackEventsCommand } from '@aws-sdk/client-cloudformation';
35

46
const stackProgressPrinterStub = {
57
printerFn: jest.fn(),
68
addEventActivity: jest.fn(),
79
};
810

9-
const cfn = {
10-
describeStackEvents: () => ({
11-
promise: () =>
12-
Promise.resolve({
13-
NextToken: undefined,
14-
}),
15-
}),
16-
} as unknown as CloudFormation;
11+
const mockCfnClient = mockClient(CloudFormationClient);
1712

1813
jest.useFakeTimers();
1914
jest.spyOn(global, 'setTimeout');
2015
jest.spyOn(global, 'clearTimeout');
2116

2217
describe('StackEventMonitor', () => {
18+
mockCfnClient.on(DescribeStackEventsCommand).resolves({
19+
NextToken: undefined,
20+
});
21+
2322
const monitor = new StackEventMonitor(
24-
cfn,
23+
mockCfnClient as unknown as CloudFormationClient,
2524
'testStackName',
2625
stackProgressPrinterStub.printerFn,
2726
stackProgressPrinterStub.addEventActivity,

packages/amplify-provider-awscloudformation/src/__tests__/permission-boundary/permissions-boundary.test.ts

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { $TSContext, setPermissionsBoundaryArn, getPermissionsBoundaryArn, stateManager } from '@aws-amplify/amplify-cli-core';
22
import { prompt } from 'inquirer';
3-
import { IAM } from 'aws-sdk';
3+
import { GetPolicyCommand, IAMClient as IAM } from '@aws-sdk/client-iam';
44
import { configurePermissionsBoundaryForInit } from '../../permissions-boundary/permissions-boundary';
55
import { IAMClient } from '../../aws-utils/aws-iam';
6+
import { mockClient } from 'aws-sdk-client-mock';
7+
import 'aws-sdk-client-mock-jest';
68

79
const permissionsBoundaryArn = 'arn:aws:iam::123456789012:policy/some-policy-name';
810
const argName = 'permissions-boundary';
@@ -25,6 +27,7 @@ const getPermissionsBoundaryArn_mock = getPermissionsBoundaryArn as jest.MockedF
2527
const prompt_mock = prompt as jest.MockedFunction<typeof prompt>;
2628
const IAMClient_mock = IAMClient as jest.Mocked<typeof IAMClient>;
2729
const stateManager_mock = stateManager as jest.Mocked<typeof stateManager>;
30+
const mockIAMClient = mockClient(IAM);
2831

2932
stateManager_mock.getLocalEnvInfo.mockReturnValue({ envName: 'testenv' });
3033

@@ -53,6 +56,7 @@ describe('configure permissions boundary on init', () => {
5356
},
5457
} as unknown as $TSContext;
5558
jest.clearAllMocks();
59+
mockIAMClient.reset();
5660
});
5761
it('applies policy specifed in cmd arg when present', async () => {
5862
context_stub.input.options[argName] = permissionsBoundaryArn;
@@ -108,12 +112,9 @@ describe('configure permissions boundary on env add', () => {
108112
it('applies existing policy to new env when existing policy is accessible', async () => {
109113
getPermissionsBoundaryArn_mock.mockReturnValueOnce(permissionsBoundaryArn);
110114
IAMClient_mock.getInstance.mockResolvedValueOnce({
111-
client: {
112-
getPolicy: jest.fn().mockReturnValueOnce({
113-
promise: jest.fn(),
114-
}),
115-
} as unknown as IAM,
115+
client: mockIAMClient as unknown as IAM,
116116
});
117+
mockIAMClient.on(GetPolicyCommand).resolvesOnce({});
117118
await configurePermissionsBoundaryForInit(context_stub);
118119
expect(setPermissionsBoundaryArn_mock.mock.calls[0][0]).toEqual(permissionsBoundaryArn);
119120
expect(prompt_mock).not.toHaveBeenCalled();
@@ -122,12 +123,9 @@ describe('configure permissions boundary on env add', () => {
122123
it('prompts for new policy when existing one is not accessible', async () => {
123124
getPermissionsBoundaryArn_mock.mockReturnValueOnce(permissionsBoundaryArn);
124125
IAMClient_mock.getInstance.mockResolvedValueOnce({
125-
client: {
126-
getPolicy: jest.fn().mockReturnValueOnce({
127-
promise: jest.fn().mockRejectedValueOnce({ statusCode: 404, message: 'test error' }),
128-
}),
129-
} as unknown as IAM,
126+
client: mockIAMClient as unknown as IAM,
130127
});
128+
mockIAMClient.on(GetPolicyCommand).rejects({ name: 'NoSuchEntityException', message: 'test error' });
131129
const newPermissionsBoundaryArn = 'thisIsANewArn';
132130
prompt_mock.mockResolvedValueOnce({
133131
permissionsBoundaryArn: newPermissionsBoundaryArn,
@@ -140,12 +138,9 @@ describe('configure permissions boundary on env add', () => {
140138
context_stub.input.options.yes = true;
141139
getPermissionsBoundaryArn_mock.mockReturnValueOnce(permissionsBoundaryArn);
142140
IAMClient_mock.getInstance.mockResolvedValueOnce({
143-
client: {
144-
getPolicy: jest.fn().mockReturnValueOnce({
145-
promise: jest.fn().mockRejectedValueOnce({ statusCode: 404, message: 'test error' }),
146-
}),
147-
} as unknown as IAM,
141+
client: mockIAMClient as unknown as IAM,
148142
});
143+
mockIAMClient.on(GetPolicyCommand).rejects({ name: 'NoSuchEntityException', message: 'test error' });
149144
await expect(configurePermissionsBoundaryForInit(context_stub)).rejects.toMatchInlineSnapshot(
150145
`[InputValidationError: A permissions boundary ARN must be specified using --permissions-boundary]`,
151146
);

packages/amplify-provider-awscloudformation/src/__tests__/utils/amplify-resource-state-utils.test.ts

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,49 @@
1+
import { CloudFormationClient, DescribeStackResourcesCommand, DescribeStacksCommand } from '@aws-sdk/client-cloudformation';
12
import { getTableNames, getPreviousDeploymentRecord } from '../../utils/amplify-resource-state-utils';
2-
import { CloudFormation } from 'aws-sdk';
3+
import { mockClient } from 'aws-sdk-client-mock';
4+
import 'aws-sdk-client-mock-jest';
35

4-
const cfnClientStub = {
5-
describeStackResources: () => ({
6-
promise: () =>
7-
Promise.resolve({
8-
StackResources: [
6+
const mockCfnClient = mockClient(CloudFormationClient);
7+
mockCfnClient
8+
.on(DescribeStackResourcesCommand)
9+
.resolves({
10+
StackResources: [
11+
{
12+
LogicalResourceId: 'LogicalResourceIdTest1',
13+
PhysicalResourceId: 'PhysicalResourceIdTest',
14+
ResourceType: undefined,
15+
Timestamp: undefined,
16+
ResourceStatus: undefined,
17+
},
18+
],
19+
})
20+
.on(DescribeStacksCommand)
21+
.resolves({
22+
Stacks: [
23+
{
24+
Outputs: [
925
{
10-
LogicalResourceId: 'LogicalResourceIdTest1',
11-
PhysicalResourceId: 'PhysicalResourceIdTest',
26+
OutputKey: 'GetAttLogicalResourceIdTest1TableName',
27+
OutputValue: 'TestStackOutputValue1',
28+
},
29+
{
30+
OutputKey: 'InvalidLogicalResourceIdTableName',
31+
OutputValue: 'TestStackOutputValue2',
1232
},
1333
],
14-
}),
15-
}),
16-
describeStacks: () => ({
17-
promise: () =>
18-
Promise.resolve({
19-
Stacks: [
34+
Parameters: [
2035
{
21-
Outputs: [
22-
{
23-
OutputKey: 'GetAttLogicalResourceIdTest1TableName',
24-
OutputValue: 'TestStackOutputValue1',
25-
},
26-
{
27-
OutputKey: 'InvalidLogicalResourceIdTableName',
28-
OutputValue: 'TestStackOutputValue2',
29-
},
30-
],
31-
Parameters: [
32-
{
33-
ParameterKey: 'TestParameterKey1',
34-
ParameterValue: 'TestParameterValue1',
35-
},
36-
],
37-
Capabilities: ['CAPABILITY_IAM'],
36+
ParameterKey: 'TestParameterKey1',
37+
ParameterValue: 'TestParameterValue1',
3838
},
3939
],
40-
}),
41-
}),
42-
} as unknown as CloudFormation;
40+
Capabilities: ['CAPABILITY_IAM'],
41+
StackName: undefined,
42+
CreationTime: undefined,
43+
StackStatus: undefined,
44+
},
45+
],
46+
});
4347

4448
describe('amplify-resource-state-utils', () => {
4549
const StackID = 'TestSTackID';
@@ -49,7 +53,7 @@ describe('amplify-resource-state-utils', () => {
4953
const expectedTableNameMap: Map<string, string> = new Map();
5054
expectedTableNameMap.set('LogicalResourceIdTest1', 'TestStackOutputValue1');
5155

52-
const tableNames = await getTableNames(cfnClientStub, tables, StackID);
56+
const tableNames = await getTableNames(mockCfnClient as unknown as CloudFormationClient, tables, StackID);
5357
expect(tableNames).toEqual(expectedTableNameMap);
5458
});
5559

@@ -58,7 +62,7 @@ describe('amplify-resource-state-utils', () => {
5862
capabilities: ['CAPABILITY_IAM'],
5963
parameters: { TestParameterKey1: 'TestParameterValue1' },
6064
};
61-
const prevDeploymentRecord = await getPreviousDeploymentRecord(cfnClientStub, StackID);
65+
const prevDeploymentRecord = await getPreviousDeploymentRecord(mockCfnClient as unknown as CloudFormationClient, StackID);
6266

6367
expect(prevDeploymentRecord).toEqual(expectedPrevDeploymentRecord);
6468
});

0 commit comments

Comments
 (0)