Skip to content

Commit d3dd20a

Browse files
authored
Add functional tests (#19)
This commit adds tests which run the script within a separate shell instance and verifies that the script makes the appropriate changes to the repo. I've tried to make these functional tests as readable as possible. In order to do that, I created a small framework which replicates the environment in which the script will run and then allows that environment to be modified per-test to suit the assertions being made.
1 parent 603d122 commit d3dd20a

20 files changed

+1338
-91
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"@types/yargs": "^17.0.10",
5050
"@typescript-eslint/eslint-plugin": "^4.21.0",
5151
"@typescript-eslint/parser": "^4.21.0",
52+
"deepmerge": "^4.2.2",
5253
"eslint": "^7.23.0",
5354
"eslint-config-prettier": "^8.1.0",
5455
"eslint-plugin-import": "^2.22.1",

src/fs.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import util from 'util';
44
import rimraf from 'rimraf';
55
import { when } from 'jest-when';
66
import * as actionUtils from '@metamask/action-utils';
7-
import { withSandbox } from '../tests/unit/helpers';
7+
import { withSandbox } from '../tests/helpers';
88
import {
99
readFile,
1010
writeFile,

src/functional.test.ts

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
import { withMonorepoProjectEnvironment } from '../tests/functional/helpers/with';
2+
import { buildChangelog } from '../tests/functional/helpers/utils';
3+
4+
describe('create-release-branch (functional)', () => {
5+
describe('against a monorepo with independent versions', () => {
6+
it('updates the version of the root package to be the current date along with the versions of the specified packages', async () => {
7+
await withMonorepoProjectEnvironment(
8+
{
9+
packages: {
10+
$root$: {
11+
name: '@scope/monorepo',
12+
version: '2022.1.1',
13+
directoryPath: '.',
14+
},
15+
a: {
16+
name: '@scope/a',
17+
version: '0.1.2',
18+
directoryPath: 'packages/a',
19+
},
20+
b: {
21+
name: '@scope/b',
22+
version: '1.1.4',
23+
directoryPath: 'packages/b',
24+
},
25+
c: {
26+
name: '@scope/c',
27+
version: '2.0.13',
28+
directoryPath: 'packages/c',
29+
},
30+
d: {
31+
name: '@scope/d',
32+
version: '1.2.3',
33+
directoryPath: 'packages/d',
34+
},
35+
e: {
36+
name: '@scope/e',
37+
version: '0.0.3',
38+
directoryPath: 'packages/e',
39+
},
40+
},
41+
workspaces: {
42+
'.': ['packages/*'],
43+
},
44+
today: new Date('2022-06-24'),
45+
},
46+
async (environment) => {
47+
await environment.runTool({
48+
releaseSpecification: {
49+
packages: {
50+
a: 'major',
51+
b: 'minor',
52+
c: 'patch',
53+
d: '1.2.4',
54+
},
55+
},
56+
});
57+
58+
expect(await environment.readJsonFile('package.json')).toMatchObject({
59+
version: '2022.6.24',
60+
});
61+
expect(
62+
await environment.readJsonFileWithinPackage('a', 'package.json'),
63+
).toMatchObject({
64+
version: '1.0.0',
65+
});
66+
expect(
67+
await environment.readJsonFileWithinPackage('b', 'package.json'),
68+
).toMatchObject({
69+
version: '1.2.0',
70+
});
71+
expect(
72+
await environment.readJsonFileWithinPackage('c', 'package.json'),
73+
).toMatchObject({
74+
version: '2.0.14',
75+
});
76+
expect(
77+
await environment.readJsonFileWithinPackage('d', 'package.json'),
78+
).toMatchObject({
79+
version: '1.2.4',
80+
});
81+
expect(
82+
await environment.readJsonFileWithinPackage('e', 'package.json'),
83+
).toMatchObject({
84+
version: '0.0.3',
85+
});
86+
},
87+
);
88+
});
89+
90+
it("updates each of the specified packages' changelogs by adding a new section which lists all commits concerning the package over the entire history of the repo", async () => {
91+
await withMonorepoProjectEnvironment(
92+
{
93+
packages: {
94+
$root$: {
95+
name: '@scope/monorepo',
96+
version: '2022.1.1',
97+
directoryPath: '.',
98+
},
99+
a: {
100+
name: '@scope/a',
101+
version: '1.0.0',
102+
directoryPath: 'packages/a',
103+
},
104+
b: {
105+
name: '@scope/b',
106+
version: '1.0.0',
107+
directoryPath: 'packages/b',
108+
},
109+
},
110+
workspaces: {
111+
'.': ['packages/*'],
112+
},
113+
createInitialCommit: false,
114+
},
115+
async (environment) => {
116+
// Create an initial commit
117+
await environment.writeFileWithinPackage(
118+
'a',
119+
'CHANGELOG.md',
120+
buildChangelog(`
121+
## [Unreleased]
122+
123+
[Unreleased]: https://github.com/example-org/example-repo
124+
`),
125+
);
126+
await environment.writeFileWithinPackage(
127+
'b',
128+
'CHANGELOG.md',
129+
buildChangelog(`
130+
## [Unreleased]
131+
132+
[Unreleased]: https://github.com/example-org/example-repo
133+
`),
134+
);
135+
await environment.createCommit('Initial commit');
136+
137+
// Create another commit that only changes "a"
138+
await environment.writeFileWithinPackage(
139+
'a',
140+
'dummy.txt',
141+
'Some content',
142+
);
143+
await environment.createCommit('Update "a"');
144+
145+
// Run the tool
146+
await environment.runTool({
147+
releaseSpecification: {
148+
packages: {
149+
a: 'major',
150+
b: 'major',
151+
},
152+
},
153+
});
154+
155+
// Both changelogs should get updated, with an additional
156+
// commit listed for "a"
157+
expect(
158+
await environment.readFileWithinPackage('a', 'CHANGELOG.md'),
159+
).toStrictEqual(
160+
buildChangelog(`
161+
## [Unreleased]
162+
163+
## [2.0.0]
164+
### Uncategorized
165+
- Update "a"
166+
- Initial commit
167+
168+
[Unreleased]: https://github.com/example-org/example-repo/compare/v2.0.0...HEAD
169+
[2.0.0]: https://github.com/example-org/example-repo/releases/tag/v2.0.0
170+
`),
171+
);
172+
expect(
173+
await environment.readFileWithinPackage('b', 'CHANGELOG.md'),
174+
).toStrictEqual(
175+
buildChangelog(`
176+
## [Unreleased]
177+
178+
## [2.0.0]
179+
### Uncategorized
180+
- Initial commit
181+
182+
[Unreleased]: https://github.com/example-org/example-repo/compare/v2.0.0...HEAD
183+
[2.0.0]: https://github.com/example-org/example-repo/releases/tag/v2.0.0
184+
`),
185+
);
186+
},
187+
);
188+
});
189+
190+
it('switches to a new release branch and commits the changes', async () => {
191+
await withMonorepoProjectEnvironment(
192+
{
193+
packages: {
194+
$root$: {
195+
name: '@scope/monorepo',
196+
version: '2022.1.1',
197+
directoryPath: '.',
198+
},
199+
a: {
200+
name: '@scope/a',
201+
version: '1.0.0',
202+
directoryPath: 'packages/a',
203+
},
204+
},
205+
workspaces: {
206+
'.': ['packages/*'],
207+
},
208+
today: new Date('2022-06-24'),
209+
},
210+
async (environment) => {
211+
await environment.runTool({
212+
releaseSpecification: {
213+
packages: {
214+
a: 'major',
215+
},
216+
},
217+
});
218+
219+
// Tests four things:
220+
// * The latest commit should be called "Release YYYY-MM-DD"
221+
// * The latest commit should be the current commit (HEAD)
222+
// * The latest branch should be called "release/YYYY-MM-DD"
223+
// * The latest branch should point to the latest commit
224+
const [latestCommitSubject, latestCommitId, latestCommitRevsMarker] =
225+
(
226+
await environment.runCommand('git', [
227+
'log',
228+
'--pretty=%s%x09%H%x09%D',
229+
'--date-order',
230+
'--max-count=1',
231+
])
232+
).stdout.split('\x09');
233+
const latestCommitRevs = latestCommitRevsMarker.split(' -> ');
234+
const latestBranchCommitId = (
235+
await environment.runCommand('git', [
236+
'rev-list',
237+
'--branches',
238+
'--date-order',
239+
'--max-count=1',
240+
])
241+
).stdout;
242+
expect(latestCommitSubject).toStrictEqual('Release 2022-06-24');
243+
expect(latestCommitRevs).toContain('HEAD');
244+
expect(latestCommitRevs).toContain('release/2022-06-24');
245+
expect(latestBranchCommitId).toStrictEqual(latestCommitId);
246+
},
247+
);
248+
});
249+
});
250+
});

src/monorepo-workflow-operations.test.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
import fs from 'fs';
22
import path from 'path';
33
import { SemVer } from 'semver';
4-
import {
5-
withSandbox,
6-
buildMockPackage,
7-
buildMockProject,
8-
} from '../tests/unit/helpers';
4+
import { withSandbox } from '../tests/helpers';
5+
import { buildMockPackage, buildMockProject } from '../tests/unit/helpers';
96
import { followMonorepoWorkflow } from './monorepo-workflow-operations';
107
import * as editorModule from './editor';
118
import * as envModule from './env';

src/package-manifest.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import fs from 'fs';
22
import path from 'path';
33
import { SemVer } from 'semver';
4-
import { withSandbox } from '../tests/unit/helpers';
4+
import { withSandbox } from '../tests/helpers';
55
import { readPackageManifest } from './package-manifest';
66

77
describe('package-manifest', () => {

src/package.test.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,10 @@ import fs from 'fs';
22
import path from 'path';
33
import { when } from 'jest-when';
44
import * as autoChangelog from '@metamask/auto-changelog';
5-
import {
6-
buildMockProject,
7-
buildMockManifest,
8-
withSandbox,
9-
} from '../tests/unit/helpers';
10-
import { readPackage, updatePackage } from './package';
5+
import { withSandbox } from '../tests/helpers';
6+
import { buildMockProject, buildMockManifest } from '../tests/unit/helpers';
117
import * as fsModule from './fs';
8+
import { readPackage, updatePackage } from './package';
129
import * as packageManifestModule from './package-manifest';
1310

1411
jest.mock('@metamask/auto-changelog');

src/project.test.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
import fs from 'fs';
22
import path from 'path';
33
import { when } from 'jest-when';
4-
import {
5-
buildMockManifest,
6-
buildMockPackage,
7-
withSandbox,
8-
} from '../tests/unit/helpers';
4+
import { withSandbox } from '../tests/helpers';
5+
import { buildMockManifest, buildMockPackage } from '../tests/unit/helpers';
96
import { readProject } from './project';
107
import * as packageModule from './package';
118
import * as repoModule from './repo';

src/release-specification.test.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,8 @@ import { when } from 'jest-when';
44
import { MockWritable } from 'stdio-mock';
55
import YAML from 'yaml';
66
import { SemVer } from 'semver';
7-
import {
8-
withSandbox,
9-
buildMockProject,
10-
buildMockPackage,
11-
} from '../tests/unit/helpers';
7+
import { withSandbox } from '../tests/helpers';
8+
import { buildMockProject, buildMockPackage } from '../tests/unit/helpers';
129
import {
1310
generateReleaseSpecificationTemplateForMonorepo,
1411
waitForUserToEditReleaseSpecification,
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import path from 'path';
2+
3+
const ROOT_DIR = path.resolve(__dirname, '../../..');
4+
export const TOOL_EXECUTABLE_PATH = path.join(ROOT_DIR, 'src', 'cli.ts');
5+
export const TS_NODE_PATH = path.join(
6+
ROOT_DIR,
7+
'node_modules',
8+
'.bin',
9+
'ts-node',
10+
);

0 commit comments

Comments
 (0)