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: unit tests + e2e tests for custom resources #8602

Merged
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
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ module.exports = {
'/packages/amplify-category-auth/resources/auth-custom-resource',
'/packages/amplify-category-custom/lib',
'/packages/amplify-category-custom/resources',
'/packages/amplify-category-custom/src/utils/build-custom-resources.ts',
'/packages/amplify-category-custom/src/utils/generate-cfn-from-cdk.ts',

// Ignore CHANGELOG.md files
'/packages/*/CHANGELOG.md',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/* Add Amplify Helper dependencies */
import { AmplifyAuthCognitoStackTemplate } from '@aws-amplify/cli-overrides-helper';

/* TODO: Need to change props to Root-Stack specific props when props are ready */
export function overrideProps(props: any): void {
/* TODO: Add snippet of how to override in comments */
export function overrideProps(props: AmplifyAuthCognitoStackTemplate) {
kaustavghosh06 marked this conversation as resolved.
Show resolved Hide resolved
return props;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
},
"dependencies": {
"@types/fs-extra": "^9.0.11",
"fs-extra": "^9.1.0"
"fs-extra": "^9.1.0",
"@aws-amplify/cli-overrides-helper": "1.1.0-ext9.0"
kaustavghosh06 marked this conversation as resolved.
Show resolved Hide resolved
},
"devDependencies": {
"typescript": "^4.2.4"
Expand Down
7 changes: 4 additions & 3 deletions packages/amplify-category-custom/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"types": "lib/index.d.ts",
"scripts": {
"build": "tsc",
"test": "jest",
"clean": "rimraf lib tsconfig.tsbuildinfo",
"watch": "tsc -w"
},
Expand Down Expand Up @@ -51,9 +52,9 @@
"node"
],
"collectCoverage": true,
"coverageReporters": [
"json",
"html"
"collectCoverageFrom": [
"src/**/*.ts",
"!**/*.d.ts"
]
}
}
6 changes: 6 additions & 0 deletions packages/amplify-category-custom/resources/cdk-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ export class cdkStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);

/* Do not remove - Amplify CLI automatically injects the current deployment environment in this input paramater */
new cdk.CfnParameter(this, 'env', {
type: 'String',
description: 'Current Amplify CLI env name',
});

/* AWS CDK Code goes here - Learn more: https://docs.aws.amazon.com/cdk/latest/guide/home.html */

/* Example 1: Set up an SQS queue with an SNS topic
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { $TSContext } from 'amplify-cli-core';
import { run } from '../../commands/custom/add';
import { customDeploymentOptionsQuestion } from '../../utils/common-questions';
import { CDK_DEPLOYMENT_NAME, CFN_DEPLOYMENT_NAME } from '../../utils/constants';
import { addCDKWalkthrough } from '../../walkthroughs/cdk-walkthrough';
import { addCloudFormationWalkthrough } from '../../walkthroughs/cloudformation-walkthrough';

jest.mock('../../utils/common-questions');
jest.mock('../../walkthroughs/cloudformation-walkthrough');
jest.mock('../../walkthroughs/cdk-walkthrough');

const addCloudFormationWalkthrough_mock = addCloudFormationWalkthrough as jest.MockedFunction<typeof addCloudFormationWalkthrough>;
const addCDKWalkthrough_mock = addCDKWalkthrough as jest.MockedFunction<typeof addCDKWalkthrough>;
const customDeploymentOptionsQuestion_mock = customDeploymentOptionsQuestion as jest.MockedFunction<typeof customDeploymentOptionsQuestion>;

describe('add custom flow', () => {
let mockContext: $TSContext;

beforeEach(() => {
jest.clearAllMocks();
mockContext = {
amplify: {},
} as unknown as $TSContext;
});

it('add custom workflow is invoked for CDK', async () => {
customDeploymentOptionsQuestion_mock.mockResolvedValueOnce(CDK_DEPLOYMENT_NAME);

await run(mockContext);
expect(addCDKWalkthrough_mock).toHaveBeenCalledTimes(1);
});

it('add custom workflow is invoked for CFN', async () => {
customDeploymentOptionsQuestion_mock.mockResolvedValueOnce(CFN_DEPLOYMENT_NAME);

await run(mockContext);
expect(addCloudFormationWalkthrough_mock).toHaveBeenCalledTimes(1);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { $TSContext } from 'amplify-cli-core';
import { run } from '../../commands/custom/build';
import { buildCustomResources } from '../../utils/build-custom-resources';

jest.mock('../../utils/build-custom-resources');
const buildCustomResources_mock = buildCustomResources as jest.MockedFunction<typeof buildCustomResources>;

describe('build custom resources flow', () => {
let mockContext: $TSContext;

beforeEach(() => {
jest.clearAllMocks();
mockContext = {
amplify: {},
parameters: {},
} as unknown as $TSContext;
});

it('build all custom resources', async () => {
await run(mockContext);

expect(buildCustomResources_mock).toHaveBeenCalledWith(mockContext, undefined);
});

it('build one custom resource', async () => {
const mockResourceName = 'mockresourcename';
mockContext.parameters.first = mockResourceName;

await run(mockContext);
expect(buildCustomResources_mock).toHaveBeenCalledWith(mockContext, mockResourceName);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { $TSContext } from 'amplify-cli-core';
import { run } from '../../commands/custom/remove';

jest.mock('amplify-cli-core');

describe('remove custom resource command tests', () => {
let mockContext: $TSContext;

beforeEach(() => {
jest.clearAllMocks();
mockContext = {
amplify: {},
parameters: {},
} as unknown as $TSContext;
});

it('remove resource workflow is invoked for custom resources with no params', async () => {
mockContext.amplify.removeResource = jest.fn().mockImplementation(async () => {
return;
});

await run(mockContext);

expect(mockContext.amplify.removeResource).toHaveBeenCalledWith(mockContext, 'custom', undefined);
});

it('remove resource workflow is invoked for custom resource with params as resourceName', async () => {
const mockResourceName = 'mockResourceName';
mockContext.parameters.first = mockResourceName;
mockContext.amplify.removeResource = jest.fn().mockImplementation(async () => {
return;
});

await run(mockContext);

expect(mockContext.amplify.removeResource).toHaveBeenCalledWith(mockContext, 'custom', mockResourceName);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { $TSContext, pathManager, stateManager } from 'amplify-cli-core';
import { prompter } from 'amplify-prompts';
import { run } from '../../commands/custom/update';
import { CDK_SERVICE_NAME, CFN_SERVICE_NAME } from '../../utils/constants';
import { updateCloudFormationWalkthrough } from '../../walkthroughs/cloudformation-walkthrough';

jest.mock('../../walkthroughs/cloudformation-walkthrough');
jest.mock('amplify-cli-core');
jest.mock('amplify-prompts');

let mockAmplifyMeta = {
custom: {
mockcdkresourcename: {
service: CDK_SERVICE_NAME,
providerPlugin: 'awscloudformation',
},
mockcfnresourcename: {
service: CFN_SERVICE_NAME,
providerPlugin: 'awscloudformation',
},
},
};

stateManager.getMeta = jest.fn().mockReturnValue(mockAmplifyMeta);
pathManager.getBackendDirPath = jest.fn().mockReturnValue('mockTargetDir');

const updateCloudFormationWalkthrough_mock = updateCloudFormationWalkthrough as jest.MockedFunction<typeof updateCloudFormationWalkthrough>;

describe('update custom flow', () => {
let mockContext: $TSContext;

beforeEach(() => {
jest.clearAllMocks();
mockContext = {
amplify: {
openEditor: jest.fn(),
},
} as unknown as $TSContext;
});

it('update custom workflow is invoked for a CFN resource', async () => {
prompter.pick = jest.fn().mockReturnValueOnce('mockcfnresourcename');

await run(mockContext);
expect(updateCloudFormationWalkthrough_mock).toHaveBeenCalledWith(mockContext, 'mockcfnresourcename');
});

it('update custom workflow is invoked for a CDK resource', async () => {
prompter.pick = jest.fn().mockReturnValueOnce('mockcdkresourcename');

prompter.yesOrNo = jest.fn().mockReturnValueOnce(true);

await run(mockContext);

expect(mockContext.amplify.openEditor).toHaveBeenCalledTimes(1);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { $TSContext } from 'amplify-cli-core';
import execa from 'execa';
import { buildCustomResources } from '../../utils/build-custom-resources';

jest.mock('amplify-cli-core');
jest.mock('amplify-prompts');
jest.mock('../../utils/dependency-management-utils');
jest.mock('../../utils/generate-cfn-from-cdk');
jest.mock('execa');
jest.mock('ora');

jest.mock('fs-extra', () => ({
readFileSync: jest.fn().mockReturnValue('mockCode'),
existsSync: jest.fn().mockReturnValue(true),
ensureDirSync: jest.fn().mockReturnValue(true),
writeFileSync: jest.fn().mockReturnValue(true),
}));

jest.mock('ora', () => {
return () => ({
start: jest.fn(),
fail: jest.fn(),
succeed: jest.fn(),
stop: jest.fn(),
});
});

jest.mock('../../utils/dependency-management-utils', () => ({
getAllResources: jest.fn().mockResolvedValue({ mockedvalue: 'mockedkey' }),
}));

jest.mock('../../utils/generate-cfn-from-cdk', () => ({
generateCloudFormationFromCDK: jest.fn(),
}));

jest.mock('amplify-cli-core', () => ({
getPackageManager: jest.fn().mockResolvedValue('npm'),
pathManager: {
getBackendDirPath: jest.fn().mockReturnValue('mockTargetDir'),
},
JSONUtilities: {
writeJson: jest.fn(),
readJson: jest.fn(),
},
}));

describe('build custom resources scenarios', () => {
let mockContext: $TSContext;

beforeEach(() => {
jest.clearAllMocks();
mockContext = {
amplify: {
openEditor: jest.fn(),
updateamplifyMetaAfterResourceAdd: jest.fn(),
copyBatch: jest.fn(),
getResourceStatus: jest.fn().mockResolvedValue({
allResources: [
{
resourceName: 'mockresource1',
service: 'customCDK',
},
{
resourceName: 'mockresource2',
service: 'customCDK',
},
],
}),
},
} as unknown as $TSContext;
});

it('build all resources', async () => {
await buildCustomResources(mockContext);

// 2 for npm install and 2 for tsc build (1 per resource)
expect(execa.sync).toBeCalledTimes(4);
});
});
Loading