Skip to content

Commit

Permalink
test(core): refactor tests and add more scenarios
Browse files Browse the repository at this point in the history
  • Loading branch information
JamieMason committed May 2, 2022
1 parent e571775 commit d37ad27
Show file tree
Hide file tree
Showing 20 changed files with 379 additions and 226 deletions.
9 changes: 5 additions & 4 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ module.exports = {
coverageReporters: ['html', 'lcov'],
coverageThreshold: {
global: {
branches: 69,
functions: 83,
lines: 81,
statements: 80,
branches: 79,
functions: 93,
lines: 93,
statements: 92,
},
},
moduleFileExtensions: ['ts', 'js'],
setupFiles: ['<rootDir>/test/jest.setup.ts'],
testMatch: ['<rootDir>/src/**/*.spec.(ts|js)'],
transform: {
'^.+\\.ts$': 'ts-jest',
Expand Down
216 changes: 33 additions & 183 deletions src/bin-fix-mismatches/fix-mismatches.spec.ts
Original file line number Diff line number Diff line change
@@ -1,207 +1,57 @@
import 'expect-more-jest';
import { wrapper } from '../../test/mock';
import { mockDisk } from '../../test/mock-disk';
import { scenarios } from '../../test/scenarios';
import { getInput } from '../lib/get-input';
import { fixMismatches } from './fix-mismatches';

describe('fixMismatches', () => {
describe('when dependencies are installed with different versions', () => {
describe('when the dependency is not a package maintained in this workspace', () => {
it('uses the highest version', () => {
const disk = mockDisk();
const aBefore = wrapper('a', ['foo@0.1.0']);
const bBefore = wrapper('b', [], ['foo@0.2.0']);
const aAfter = wrapper('a', ['foo@0.2.0']);
const log = jest
.spyOn(console, 'log')
.mockImplementation(() => undefined);
disk.globSync.mockImplementation((glob) => {
if (glob.endsWith('packages/*/package.json')) {
return ['packages/a/package.json', 'packages/b/package.json'];
}
});
disk.readFileSync.mockImplementation((filePath) => {
if (filePath.endsWith('packages/a/package.json')) {
return aBefore.json;
}
if (filePath.endsWith('packages/b/package.json')) {
return bBefore.json;
}
});
fixMismatches(getInput(disk, {}), disk);
expect(disk.writeFileSync.mock.calls).toEqual([
[expect.stringContaining('packages/a/package.json'), aAfter.json],
]);
expect(log.mock.calls).toEqual([
[
expect.stringMatching(//),
expect.stringMatching('packages/a/package.json'),
],
[
expect.stringMatching(/-/),
expect.stringMatching('packages/b/package.json'),
],
]);
log.mockRestore();
});
});
beforeEach(() => {
jest.restoreAllMocks();
});

describe('when dependencies are installed with different versions', () => {
describe('when the dependency is a package maintained in this workspace', () => {
it('uses the workspace version', () => {
const disk = mockDisk();
const aBefore = wrapper('a', ['foo@0.1.0']);
const bBefore = wrapper('b', [], ['foo@0.2.0']);
const fooBefore = wrapper('foo', [], [], [], {
name: 'foo',
version: '0.0.1',
});
const aAfter = wrapper('a', ['foo@0.0.1']);
const bAfter = wrapper('b', [], ['foo@0.0.1']);
const log = jest
.spyOn(console, 'log')
.mockImplementation(() => undefined);
disk.globSync.mockImplementation((glob) => {
if (glob.endsWith('packages/*/package.json')) {
return [
'packages/a/package.json',
'packages/b/package.json',
'packages/foo/package.json',
];
}
});
disk.readFileSync.mockImplementation((filePath) => {
if (filePath.endsWith('packages/a/package.json')) return aBefore.json;
if (filePath.endsWith('packages/b/package.json')) return bBefore.json;
if (filePath.endsWith('packages/foo/package.json'))
return fooBefore.json;
});
fixMismatches(getInput(disk, {}), disk);
expect(disk.writeFileSync.mock.calls).toEqual([
[expect.stringContaining('packages/a/package.json'), aAfter.json],
[expect.stringContaining('packages/b/package.json'), bAfter.json],
const scenario = scenarios.dependentDoesNotMatchWorkspaceVersion();
fixMismatches(getInput(scenario.disk, scenario.config), scenario.disk);
expect(scenario.disk.writeFileSync.mock.calls).toEqual([
scenario.files['packages/a/package.json'].diskWriteWhenChanged,
scenario.files['packages/b/package.json'].diskWriteWhenChanged,
]);
expect(log.mock.calls).toEqual([
[
expect.stringMatching(//),
expect.stringMatching('packages/a/package.json'),
],
[
expect.stringMatching(//),
expect.stringMatching('packages/b/package.json'),
],
[
expect.stringMatching(/-/),
expect.stringMatching('packages/foo/package.json'),
],
expect(scenario.log.mock.calls).toEqual([
scenario.files['packages/a/package.json'].logEntryWhenChanged,
scenario.files['packages/b/package.json'].logEntryWhenChanged,
scenario.files['packages/c/package.json'].logEntryWhenUnchanged,
]);
log.mockRestore();
});
});

it('replaces non-semver dependencies with valid semver dependencies', () => {
const disk = mockDisk();
const aBefore = wrapper('a', ['foo@link:vendor/foo-0.1.0']);
const bBefore = wrapper('b', ['foo@link:vendor/foo-0.2.0']);
const cBefore = wrapper('c', ['foo@0.3.0']);
const dBefore = wrapper('d', ['foo@0.2.0']);
const aAfter = wrapper('a', ['foo@0.3.0']);
const bAfter = wrapper('b', ['foo@0.3.0']);
const dAfter = wrapper('d', ['foo@0.3.0']);
const log = jest
.spyOn(console, 'log')
.mockImplementation(() => undefined);
disk.globSync.mockImplementation((glob) => {
if (glob.endsWith('packages/*/package.json')) {
return [
'packages/a/package.json',
'packages/b/package.json',
'packages/c/package.json',
'packages/d/package.json',
];
}
});
disk.readFileSync.mockImplementation((filePath) => {
if (filePath.endsWith('packages/a/package.json')) return aBefore.json;
if (filePath.endsWith('packages/b/package.json')) return bBefore.json;
if (filePath.endsWith('packages/c/package.json')) return cBefore.json;
if (filePath.endsWith('packages/d/package.json')) return dBefore.json;
});
fixMismatches(getInput(disk, {}), disk);
expect(disk.writeFileSync.mock.calls).toEqual([
[expect.stringContaining('packages/a/package.json'), aAfter.json],
[expect.stringContaining('packages/b/package.json'), bAfter.json],
[expect.stringContaining('packages/d/package.json'), dAfter.json],
const scenario = scenarios.mismatchesIncludeNonSemverVersions();
fixMismatches(getInput(scenario.disk, scenario.config), scenario.disk);
expect(scenario.disk.writeFileSync.mock.calls).toEqual([
scenario.files['packages/a/package.json'].diskWriteWhenChanged,
scenario.files['packages/b/package.json'].diskWriteWhenChanged,
scenario.files['packages/d/package.json'].diskWriteWhenChanged,
]);
expect(log.mock.calls).toEqual([
[
expect.stringMatching(//),
expect.stringMatching('packages/a/package.json'),
],
[
expect.stringMatching(//),
expect.stringMatching('packages/b/package.json'),
],
[
expect.stringMatching(/-/),
expect.stringMatching('packages/c/package.json'),
],
[
expect.stringMatching(//),
expect.stringMatching('packages/d/package.json'),
],
expect(scenario.log.mock.calls).toEqual([
scenario.files['packages/a/package.json'].logEntryWhenChanged,
scenario.files['packages/b/package.json'].logEntryWhenChanged,
scenario.files['packages/c/package.json'].logEntryWhenUnchanged,
scenario.files['packages/d/package.json'].logEntryWhenChanged,
]);
log.mockRestore();
});

it('removes banned/disallowed dependencues', () => {
const disk = mockDisk();
const aBefore = wrapper('a', ['foo@0.1.0']);
const bBefore = wrapper('b', ['bar@0.2.0']);
const bAfter = wrapper('b');
const log = jest
.spyOn(console, 'log')
.mockImplementation(() => undefined);
disk.globSync.mockImplementation((glob) => {
if (glob.endsWith('packages/*/package.json')) {
return ['packages/a/package.json', 'packages/b/package.json'];
}
});
disk.readFileSync.mockImplementation((filePath) => {
if (filePath.endsWith('packages/a/package.json')) {
return aBefore.json;
}
if (filePath.endsWith('packages/b/package.json')) {
return bBefore.json;
}
});
fixMismatches(
getInput(disk, {
versionGroups: [
{
dependencies: ['bar'],
packages: ['**'],
isBanned: true,
},
],
}),
disk,
);
expect(disk.writeFileSync.mock.calls).toEqual([
[expect.stringContaining('packages/b/package.json'), bAfter.json],
it('removes banned/disallowed dependencies', () => {
const scenario = scenarios.dependencyIsBanned();
fixMismatches(getInput(scenario.disk, scenario.config), scenario.disk);
expect(scenario.disk.writeFileSync.mock.calls).toEqual([
scenario.files['packages/b/package.json'].diskWriteWhenChanged,
]);
expect(log.mock.calls).toEqual([
expect(scenario.log.mock.calls).toEqual([
[expect.stringMatching(/Version Group 1/)],
[
expect.stringMatching(/-/),
expect.stringMatching('packages/a/package.json'),
],
[
expect.stringMatching(//),
expect.stringMatching('packages/b/package.json'),
],
scenario.files['packages/a/package.json'].logEntryWhenUnchanged,
scenario.files['packages/b/package.json'].logEntryWhenChanged,
]);

log.mockRestore();
});
});
});
1 change: 1 addition & 0 deletions src/bin-lint-semver-ranges/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,5 @@ lintSemverRanges(
source: program.opts().source,
workspace: program.opts().workspace,
}),
disk,
);
19 changes: 19 additions & 0 deletions src/bin-lint-semver-ranges/lint-semver-ranges.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import 'expect-more-jest';
import { scenarios } from '../../test/scenarios';
import { getInput } from '../lib/get-input';
import { lintSemverRanges } from './lint-semver-ranges';

describe('lintSemverRanges', () => {
beforeEach(() => {
jest.restoreAllMocks();
});

it('lists versions with ranges which do not match the project config', () => {
const scenario = scenarios.semverRangesDoNotMatchConfig();
lintSemverRanges(getInput(scenario.disk, scenario.config), scenario.disk);
expect(scenario.log.mock.calls).toEqual([
['✕ bar 2.0.0 in dependencies of a should be ~2.0.0'],
['✕ foo 0.1.0 in dependencies of a should be ~0.1.0'],
]);
});
});
5 changes: 3 additions & 2 deletions src/bin-lint-semver-ranges/lint-semver-ranges.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import chalk from 'chalk';
import type { Disk } from '../lib/disk';
import type { ProgramInput } from '../lib/get-input';
import { setSemverRange } from '../lib/set-semver-range';
import { listSemverGroupMismatches } from './list-semver-group-mismatches';

export function lintSemverRanges(input: ProgramInput): void {
export function lintSemverRanges(input: ProgramInput, disk: Disk): void {
let isInvalid = false;

/**
Expand Down Expand Up @@ -33,6 +34,6 @@ export function lintSemverRanges(input: ProgramInput): void {
});

if (isInvalid) {
process.exit(1);
disk.process.exit(1);
}
}
1 change: 1 addition & 0 deletions src/bin-list-mismatches/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,5 @@ listMismatches(
source: program.opts().source,
workspace: program.opts().workspace,
}),
disk,
);
49 changes: 49 additions & 0 deletions src/bin-list-mismatches/list-mismatches.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import 'expect-more-jest';
import { scenarios } from '../../test/scenarios';
import { getInput } from '../lib/get-input';
import { listMismatches } from './list-mismatches';

describe('listMismatches', () => {
beforeEach(() => {
jest.restoreAllMocks();
});

describe('when dependencies are installed with different versions', () => {
describe('when the dependency is a package maintained in this workspace', () => {
it('warns ab the workspace version', () => {
const scenario = scenarios.dependentDoesNotMatchWorkspaceVersion();
listMismatches(getInput(scenario.disk, scenario.config), scenario.disk);
expect(scenario.log.mock.calls).toEqual([
['- c 0.0.1'],
[' 0.1.0 in dependencies of a'],
[' 0.2.0 in devDependencies of b'],
]);
expect(scenario.disk.process.exit).toHaveBeenCalledWith(1);
});
});

it('replaces non-semver dependencies with valid semver dependencies', () => {
const scenario = scenarios.mismatchesIncludeNonSemverVersions();
listMismatches(getInput(scenario.disk, scenario.config), scenario.disk);
expect(scenario.log.mock.calls).toEqual([
['- foo 0.3.0'],
[' link:vendor/foo-0.1.0 in dependencies of a'],
[' link:vendor/foo-0.2.0 in dependencies of b'],
[' 0.3.0 in dependencies of c'],
[' 0.2.0 in dependencies of d'],
]);
expect(scenario.disk.process.exit).toHaveBeenCalledWith(1);
});

it('removes banned/disallowed dependencies', () => {
const scenario = scenarios.dependencyIsBanned();
listMismatches(getInput(scenario.disk, scenario.config), scenario.disk);
expect(scenario.log.mock.calls).toEqual([
[expect.stringMatching(/Version Group 1/)],
['✕ bar remove this dependency'],
[' 0.2.0 in dependencies of b'],
]);
expect(scenario.disk.process.exit).toHaveBeenCalledWith(1);
});
});
});
5 changes: 3 additions & 2 deletions src/bin-list-mismatches/list-mismatches.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import { relative } from 'path';
import { getExpectedVersion } from '../bin-fix-mismatches/get-expected-version';
import { listVersionGroups } from '../bin-list/list-version-groups';
import { CWD } from '../constants';
import type { Disk } from '../lib/disk';
import type { ProgramInput } from '../lib/get-input';

export function listMismatches(input: ProgramInput): void {
export function listMismatches(input: ProgramInput, disk: Disk): void {
let isInvalid = false;

/**
Expand Down Expand Up @@ -48,6 +49,6 @@ export function listMismatches(input: ProgramInput): void {
});

if (isInvalid) {
process.exit(1);
disk.process.exit(1);
}
}
1 change: 1 addition & 0 deletions src/bin-list/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,5 @@ list(
source: program.opts().source,
workspace: program.opts().workspace,
}),
disk,
);

0 comments on commit d37ad27

Please sign in to comment.