Skip to content

Commit

Permalink
Add functional tests
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mcmire committed Aug 2, 2022
1 parent 603d122 commit e23c2e2
Show file tree
Hide file tree
Showing 20 changed files with 1,336 additions and 91 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"@types/yargs": "^17.0.10",
"@typescript-eslint/eslint-plugin": "^4.21.0",
"@typescript-eslint/parser": "^4.21.0",
"deepmerge": "^4.2.2",
"eslint": "^7.23.0",
"eslint-config-prettier": "^8.1.0",
"eslint-plugin-import": "^2.22.1",
Expand Down
2 changes: 1 addition & 1 deletion src/fs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import util from 'util';
import rimraf from 'rimraf';
import { when } from 'jest-when';
import * as actionUtils from '@metamask/action-utils';
import { withSandbox } from '../tests/unit/helpers';
import { withSandbox } from '../tests/helpers';
import {
readFile,
writeFile,
Expand Down
252 changes: 252 additions & 0 deletions src/functional.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
import { withMonorepoProjectEnvironment } from '../tests/functional/helpers/with';
import { buildChangelog } from '../tests/functional/helpers/utils';

describe('create-release-branch (functional)', () => {
describe('against a monorepo with independent versions', () => {
it('updates the version of the root package to be the current date along with the versions of the specified packages', async () => {
await withMonorepoProjectEnvironment(
{
packages: {
$root$: {
name: '@scope/monorepo',
version: '2022.1.1',
directoryPath: '.',
},
a: {
name: '@scope/a',
version: '0.1.2',
directoryPath: 'packages/a',
},
b: {
name: '@scope/b',
version: '1.1.4',
directoryPath: 'packages/b',
},
c: {
name: '@scope/c',
version: '2.0.13',
directoryPath: 'packages/c',
},
d: {
name: '@scope/d',
version: '1.2.3',
directoryPath: 'packages/d',
},
e: {
name: '@scope/e',
version: '0.0.3',
directoryPath: 'packages/e',
},
},
workspaces: {
'.': ['packages/*'],
},
today: new Date('2022-06-24'),
},
async (environment) => {
await environment.runTool({
releaseSpecification: {
packages: {
a: 'major',
b: 'minor',
c: 'patch',
d: '1.2.4',
},
},
});

expect(await environment.readJsonFile('package.json')).toMatchObject({
version: '2022.6.24',
});
expect(
await environment.readJsonFileWithinPackage('a', 'package.json'),
).toMatchObject({
version: '1.0.0',
});
expect(
await environment.readJsonFileWithinPackage('b', 'package.json'),
).toMatchObject({
version: '1.2.0',
});
expect(
await environment.readJsonFileWithinPackage('c', 'package.json'),
).toMatchObject({
version: '2.0.14',
});
expect(
await environment.readJsonFileWithinPackage('d', 'package.json'),
).toMatchObject({
version: '1.2.4',
});
expect(
await environment.readJsonFileWithinPackage('e', 'package.json'),
).toMatchObject({
version: '0.0.3',
});
},
);
});

it("updates each of the specified package's changelog by adding a new section which lists all commits concerning the package over the entire history of the repo", async () => {
await withMonorepoProjectEnvironment(
{
packages: {
$root$: {
name: '@scope/monorepo',
version: '1.0.0',
directoryPath: '.',
},
a: {
name: '@scope/a',
version: '1.0.0',
directoryPath: 'packages/a',
},
b: {
name: '@scope/b',
version: '1.0.0',
directoryPath: 'packages/b',
},
},
workspaces: {
'.': ['packages/*'],
},
createInitialCommit: false,
},
async (environment) => {
// Create an initial commit
await environment.writeFileWithinPackage(
'a',
'CHANGELOG.md',
buildChangelog(`
## [Unreleased]
[Unreleased]: https://github.com/example-org/example-repo
`),
);
await environment.writeFileWithinPackage(
'b',
'CHANGELOG.md',
buildChangelog(`
## [Unreleased]
[Unreleased]: https://github.com/example-org/example-repo
`),
);
await environment.createCommit('Initial commit');

// Create another commit that only changes "a"
await environment.writeFileWithinPackage(
'a',
'dummy.txt',
'Some content',
);
await environment.createCommit('Update "a"');

// Run the tool
await environment.runTool({
releaseSpecification: {
packages: {
a: 'major',
b: 'major',
},
},
});

// Both changelogs should get updated, with an additional
// commit listed for "a"
expect(
await environment.readFileWithinPackage('a', 'CHANGELOG.md'),
).toStrictEqual(
buildChangelog(`
## [Unreleased]
## [2.0.0]
### Uncategorized
- Update "a"
- Initial commit
[Unreleased]: https://github.com/example-org/example-repo/compare/v2.0.0...HEAD
[2.0.0]: https://github.com/example-org/example-repo/releases/tag/v2.0.0
`),
);
expect(
await environment.readFileWithinPackage('b', 'CHANGELOG.md'),
).toStrictEqual(
buildChangelog(`
## [Unreleased]
## [2.0.0]
### Uncategorized
- Initial commit
[Unreleased]: https://github.com/example-org/example-repo/compare/v2.0.0...HEAD
[2.0.0]: https://github.com/example-org/example-repo/releases/tag/v2.0.0
`),
);
},
);
});

it('commits the updates and saves the new commit to a new branch, then switches to that branch', async () => {
await withMonorepoProjectEnvironment(
{
packages: {
$root$: {
name: '@scope/monorepo',
version: '1.0.0',
directoryPath: '.',
},
a: {
name: '@scope/a',
version: '1.0.0',
directoryPath: 'packages/a',
},
},
workspaces: {
'.': ['packages/*'],
},
today: new Date('2022-06-24'),
},
async (environment) => {
await environment.runTool({
releaseSpecification: {
packages: {
a: 'major',
},
},
});

// The most recent commit should be called the right thing, and
// should be the current one, and should also be called
// `release/YYYY-MM-DD`
const mostRecentCommitInfo = (
await environment.runCommand('git', [
'log',
'--pretty=%D%x09%s%x09%H',
'--date-order',
'--max-count=1',
])
).stdout
.trim()
.split('\x09');
expect(mostRecentCommitInfo.slice(0, -1)).toStrictEqual([
'HEAD -> release/2022-06-24',
'Release 2022-06-24',
]);
// The most recent branch should point to the most recent commit
const commitIdOfMostRecentBranch = (
await environment.runCommand('git', [
'rev-list',
'--branches',
'--date-order',
'--max-count=1',
])
).stdout.trim();
expect(mostRecentCommitInfo[2]).toStrictEqual(
commitIdOfMostRecentBranch,
);
},
);
});
});
});
7 changes: 2 additions & 5 deletions src/monorepo-workflow-operations.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import fs from 'fs';
import path from 'path';
import { SemVer } from 'semver';
import {
withSandbox,
buildMockPackage,
buildMockProject,
} from '../tests/unit/helpers';
import { withSandbox } from '../tests/helpers';
import { buildMockPackage, buildMockProject } from '../tests/unit/helpers';
import { followMonorepoWorkflow } from './monorepo-workflow-operations';
import * as editorModule from './editor';
import * as envModule from './env';
Expand Down
2 changes: 1 addition & 1 deletion src/package-manifest.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fs from 'fs';
import path from 'path';
import { SemVer } from 'semver';
import { withSandbox } from '../tests/unit/helpers';
import { withSandbox } from '../tests/helpers';
import { readPackageManifest } from './package-manifest';

describe('package-manifest', () => {
Expand Down
9 changes: 3 additions & 6 deletions src/package.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@ import fs from 'fs';
import path from 'path';
import { when } from 'jest-when';
import * as autoChangelog from '@metamask/auto-changelog';
import {
buildMockProject,
buildMockManifest,
withSandbox,
} from '../tests/unit/helpers';
import { readPackage, updatePackage } from './package';
import { withSandbox } from '../tests/helpers';
import { buildMockProject, buildMockManifest } from '../tests/unit/helpers';
import * as fsModule from './fs';
import { readPackage, updatePackage } from './package';
import * as packageManifestModule from './package-manifest';

jest.mock('@metamask/auto-changelog');
Expand Down
7 changes: 2 additions & 5 deletions src/project.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import fs from 'fs';
import path from 'path';
import { when } from 'jest-when';
import {
buildMockManifest,
buildMockPackage,
withSandbox,
} from '../tests/unit/helpers';
import { withSandbox } from '../tests/helpers';
import { buildMockManifest, buildMockPackage } from '../tests/unit/helpers';
import { readProject } from './project';
import * as packageModule from './package';
import * as repoModule from './repo';
Expand Down
7 changes: 2 additions & 5 deletions src/release-specification.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,8 @@ import { when } from 'jest-when';
import { MockWritable } from 'stdio-mock';
import YAML from 'yaml';
import { SemVer } from 'semver';
import {
withSandbox,
buildMockProject,
buildMockPackage,
} from '../tests/unit/helpers';
import { withSandbox } from '../tests/helpers';
import { buildMockProject, buildMockPackage } from '../tests/unit/helpers';
import {
generateReleaseSpecificationTemplateForMonorepo,
waitForUserToEditReleaseSpecification,
Expand Down
10 changes: 10 additions & 0 deletions tests/functional/helpers/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import path from 'path';

export const ROOT_DIR = path.resolve(__dirname, '../../..');
export const TOOL_EXECUTABLE_PATH = path.join(ROOT_DIR, 'src', 'cli.ts');
export const TS_NODE_PATH = path.join(
ROOT_DIR,
'node_modules',
'.bin',
'ts-node',
);
Loading

0 comments on commit e23c2e2

Please sign in to comment.