Skip to content

Commit 6f10107

Browse files
authored
QOL improvements for setting up test projects (#839)
1 parent a540828 commit 6f10107

File tree

11 files changed

+121
-65
lines changed

11 files changed

+121
-65
lines changed

.changeset/spotty-roses-notice.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ lib
44
node_modules
55
temp
66
tsconfig.tsbuildinfo
7+
test-projects/*
8+
!test-projects/README.md
9+
!test-projects/.eslintrc.json
710

811
.idea
912
.eslintcache

.npmrc.local

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# this is a test config file used to publish locally
22
//localhost:4873/:_authToken=garbage
33

4-
# this prevents the script-shell setting set by install:local from being overwritten when copying the localhost config
4+
# this prevents the script-shell setting set by setup:local from being overwritten when copying the localhost config
55
script-shell=bash

CONTRIBUTING.md

Lines changed: 31 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -47,24 +47,22 @@ Also check out the README files in the root of each package directory for a brie
4747

4848
Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start.
4949

50-
## Contribute to create-amplify package
51-
52-
### Set up your local development environment
50+
## Set up your local development environment
5351

5452
```sh
5553
# clone project repo
5654
cd <project directory>
57-
npm run install:local
55+
npm run setup:local
5856
npm run test
5957
```
6058

61-
`npm run install:local` will run `npm install`, then build all packages in the project and run `npm link`
59+
`npm run setup:local` will run `npm install`, then build all packages in the project. It also links the amplify and create-amplify bin files into the project node_modules folder.
6260

6361
`npm run test` will run all the unit tests in the project
6462

65-
You should now be able to run the new `amplify` CLI.
63+
You should now be ready to start contributing to the project!
6664

67-
#### Other helpful scripts
65+
### Other helpful scripts
6866

6967
`npm run watch` will start the tsc server and watch for changes in all packages
7068

@@ -76,6 +74,30 @@ You should now be able to run the new `amplify` CLI.
7674

7775
`npm run e2e` will run the E2E test suite. Note: you must have valid AWS credentials configured locally to run this command successfully.
7876

77+
### Testing changes locally
78+
79+
For local testing we recommend writing unit tests that exercise the code you are modifying as you are making changes. Individual test files can be run using:
80+
81+
```sh
82+
npm run test:dir packages/<package name>/lib/<file-name>.test.ts
83+
```
84+
85+
> Note: You must rebuild using `npm run build` for tests to pick up your changes.
86+
87+
Sometimes it's nice to have a test project to use as a testing environment for local changes. You can create test projects in the `local-testing` directory using
88+
89+
```sh
90+
npm run setup:test-project <name>
91+
```
92+
93+
This allows you to make local changes and immediately try them out in a test project. All projects that you create in this directory are gitignored.
94+
95+
Depending on the scope of the change you are making, integration tests and/or E2E tests may be necessary.
96+
97+
Integration tests are located [here](./packages/integration-tests/src/test-in-memory/). These tests operate mostly like unit tests but they exercise many different components and packages together. However, these tests do NOT make service calls. Test assertions can be set up using the [CDK assertions library](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.assertions-readme.html).
98+
99+
E2E tests are located [here](./packages/integration-tests/src/test-e2e/). These tests exercise full end-to-end features with no mocking or stubbing. These tests do make service calls and therefore require valid AWS credentials to run. Tests should be added to this suite very sparingly as these tests are the most time consuming to run and maintain. If possible, additional features should be tested by adding on to existing tests rather than adding entirely new tests.
100+
79101
### Creating changesets
80102

81103
This repo uses [changesets](https://github.com/changesets/changesets) for versioning and releasing changes.
@@ -85,7 +107,7 @@ This will start a walkthrough to author the changeset file. This file should be
85107

86108
### Publishing packages locally
87109

88-
Publishing packages locally allows you to install local package changes as if they were published to NPM. This is useful for testing or demo scenarios.
110+
Publishing packages locally allows you to install local package changes as if they were published to NPM. This can be useful for testing or demo scenarios.
89111

90112
To set up a local npm proxy and publish the current local state to the proxy, run `npm run vend`.
91113
This will start a local npm proxy using [Verdaccio](https://verdaccio.org/) and run `changeset version` and `changeset publish`.
@@ -120,45 +142,7 @@ At a minimum, each package needs:
120142
4. An `update:api` script in the `package.json` file
121143
5. A `typedoc.json` file
122144
6. An `.npmignore` file
123-
124-
### Dev
125-
126-
1. Publish to local
127-
128-
You have to publish to local every time after making a change
129-
130-
```sh
131-
# In amplify-backend repo
132-
npm run clean
133-
npm run install:local
134-
npm run build
135-
npm run vend
136-
```
137-
138-
2. Prepare to install
139-
140-
```sh
141-
# On your local machine
142-
rm -rf $(npm config get cache)/_npx # clean npm cache globally
143-
mkdir amplify-project-$(date +%Y-%m-%d) # create an empty folder. Alternatively, you can create a project by running e.g `npx create-next-app next-$(date +%Y-%m-%d)`.
144-
cd amplify-project-$(date +%Y-%m-%d) # cd into the empty folder
145-
```
146-
147-
3. Create Amplify Project
148-
149-
```sh
150-
# In the folder created in the previous step
151-
npm create amplify
152-
```
153-
154-
### Test
155-
156-
```sh
157-
# In amplify-backend repo
158-
npm run build # Have to build every time after making a change before running test
159-
npm run test:dir packages/create-amplify # Run all test in create-amplify
160-
npm run test:dir packages/create-amplify/src/<file-name>.test.ts # Run all test in one file. e.g. npm run test:dir packages/create-amplify/src/get_project_root.test.ts
161-
```
145+
7. A `README.md` file that gives a brief description of the intent of the package
162146

163147
## Licensing
164148

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
"docs": "typedoc",
1818
"e2e": "npm run test:dir packages/integration-tests/lib/test-e2e",
1919
"e2e:cleanup-resources": "tsx scripts/cleanup_e2e_resources.ts",
20-
"install:local": "npm run set-script-shell && npm install && npm run build && npm run install:local --workspaces --if-present",
2120
"lint": "eslint --max-warnings 0 . && prettier --check .",
2221
"lint:fix": "eslint --cache --fix . && prettier --write .",
2322
"live-dependency-health-checks": "npm run test:dir packages/integration-tests/lib/test-live-dependency-health-checks",
@@ -26,6 +25,8 @@
2625
"publish": "tsx scripts/publish.ts",
2726
"publish:local": "tsx scripts/publish_local.ts",
2827
"set-script-shell": "npm config set script-shell bash --userconfig ./.npmrc",
28+
"setup:local": "npm run set-script-shell && npm install && npm run build && npm link ./packages/cli ./packages/create-amplify",
29+
"setup:test-project": "tsx scripts/setup_test_project.ts",
2930
"start:npm-proxy": "tsx scripts/start_npm_proxy.ts",
3031
"stop:npm-proxy": "tsx scripts/stop_npm_proxy.ts",
3132
"test": "npm run test:dir $(tsx scripts/get_unit_test_dir_list.ts)",

packages/cli/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@
1313
"#package.json": "./package.json"
1414
},
1515
"scripts": {
16-
"update:api": "api-extractor run --local",
17-
"install:local": "npm link"
16+
"update:api": "api-extractor run --local"
1817
},
1918
"repository": {
2019
"type": "git",

packages/create-amplify/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
"create-amplify": "./lib/create_amplify.js"
1313
},
1414
"scripts": {
15-
"install:local": "npm link",
1615
"update:api": "api-extractor run --local"
1716
},
1817
"license": "Apache-2.0",

packages/create-amplify/src/get_project_root.test.ts

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { afterEach, describe, it } from 'node:test';
1+
import { afterEach, beforeEach, describe, it, mock } from 'node:test';
22
import assert from 'assert';
33
import fsp from 'fs/promises';
44
import path from 'path';
@@ -8,6 +8,13 @@ import { AmplifyPrompter } from '@aws-amplify/cli-core';
88
const originalEnv = process.env;
99

1010
void describe('getProjectRoot', () => {
11+
const fsMkDirSyncMock = mock.method(fsp, 'mkdir', () => undefined);
12+
mock.method(fsp, 'stat', () => Promise.reject(new Error()));
13+
14+
beforeEach(() => {
15+
fsMkDirSyncMock.mock.resetCalls();
16+
});
17+
1118
afterEach(() => {
1219
process.env = originalEnv;
1320
});
@@ -18,32 +25,30 @@ void describe('getProjectRoot', () => {
1825
assert.equal(projectRoot, process.cwd());
1926
});
2027

21-
void it('returns the default project root directory if user do not pass anything', async (ctx) => {
28+
void it('returns the default project root directory if user do not pass anything', async () => {
2229
process.env.npm_config_yes = 'false';
2330
const defaultProjectRoot = '.';
24-
ctx.mock.method(AmplifyPrompter, 'input', () =>
31+
mock.method(AmplifyPrompter, 'input', () =>
2532
Promise.resolve(defaultProjectRoot)
2633
);
2734
const projectRoot = await getProjectRoot();
2835

2936
assert.equal(projectRoot, process.cwd());
3037
});
3138

32-
void it('returns the user provided project root directory', async (ctx) => {
39+
void it('returns the user provided project root directory', async () => {
3340
process.env.npm_config_yes = 'false';
3441
const userInput = path.resolve('test', 'root');
35-
ctx.mock.method(AmplifyPrompter, 'input', () => Promise.resolve(userInput));
42+
mock.method(AmplifyPrompter, 'input', () => Promise.resolve(userInput));
3643
const projectRoot = await getProjectRoot();
3744

3845
assert.equal(projectRoot, userInput);
3946
});
4047

41-
void it('creates the project root directory if the user provided absolute path does not exist', async (ctx) => {
48+
void it('creates the project root directory if the user provided absolute path does not exist', async () => {
4249
process.env.npm_config_yes = 'false';
4350
const userInput = path.resolve(process.cwd(), 'test', 'root');
44-
const fsMkDirSyncMock = ctx.mock.method(fsp, 'mkdir', () => undefined);
45-
ctx.mock.method(fsp, 'stat', () => Promise.reject(new Error()));
46-
ctx.mock.method(AmplifyPrompter, 'input', () => Promise.resolve(userInput));
51+
mock.method(AmplifyPrompter, 'input', () => Promise.resolve(userInput));
4752

4853
const projectRoot = await getProjectRoot();
4954

@@ -52,12 +57,10 @@ void describe('getProjectRoot', () => {
5257
assert.equal(projectRoot, userInput);
5358
});
5459

55-
void it('creates the project root directory if the user provided relative path does not exist', async (ctx) => {
60+
void it('creates the project root directory if the user provided relative path does not exist', async () => {
5661
process.env.npm_config_yes = 'false';
5762
const userInput = 'test';
58-
const fsMkDirSyncMock = ctx.mock.method(fsp, 'mkdir', () => undefined);
59-
ctx.mock.method(fsp, 'stat', () => Promise.reject(new Error()));
60-
ctx.mock.method(AmplifyPrompter, 'input', () => Promise.resolve(userInput));
63+
mock.method(AmplifyPrompter, 'input', () => Promise.resolve(userInput));
6164

6265
const projectRoot = await getProjectRoot();
6366

scripts/setup_test_project.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import * as fsp from 'fs/promises';
2+
import * as path from 'path';
3+
import { fileURLToPath } from 'url';
4+
5+
const projectName = process.argv[2];
6+
if (!projectName) {
7+
throw new Error('Usage: npm run setup:test-project <name>');
8+
}
9+
10+
const testProjectDir = new URL(
11+
`../test-projects/${projectName}`,
12+
import.meta.url
13+
);
14+
await fsp.mkdir(testProjectDir, { recursive: true });
15+
16+
// reaching into the create-amplify package like this isn't great, but for a test utility I think it's acceptable
17+
// if it breaks, it will only break this local script, not anything in production
18+
const createAmplifyTemplateLocation = new URL(
19+
'../packages/create-amplify/templates/basic-auth-data',
20+
import.meta.url
21+
);
22+
23+
// copy getting started project template
24+
await fsp.cp(createAmplifyTemplateLocation, testProjectDir, {
25+
recursive: true,
26+
});
27+
28+
// create minimal package.json
29+
// if you want to test out changes in a commonjs package, change the "type" field in the package.json of the test project after it is created
30+
const packageJson = {
31+
name: projectName,
32+
type: 'module',
33+
};
34+
35+
const packageJsonPath = path.join(
36+
fileURLToPath(testProjectDir),
37+
'package.json'
38+
);
39+
40+
await fsp.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
41+
42+
// create minimal tsconfig.json
43+
const tsConfig = {
44+
extends: '../../../tsconfig.base.json',
45+
compilerOptions: {
46+
moduleResolution: 'bundler',
47+
module: 'es2022',
48+
},
49+
};
50+
51+
const tsConfigPath = path.join(
52+
fileURLToPath(testProjectDir),
53+
'amplify',
54+
'tsconfig.json'
55+
);
56+
57+
await fsp.writeFile(tsConfigPath, JSON.stringify(tsConfig, null, 2));

test-projects/.eslintrc.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"rules": {
3+
"check-file/folder-naming-convention": "off"
4+
}
5+
}

0 commit comments

Comments
 (0)