Skip to content

Commit

Permalink
test: replace jest with vitest (#101)
Browse files Browse the repository at this point in the history
  • Loading branch information
Hoishin authored Dec 26, 2024
1 parent 9990349 commit d3771a6
Show file tree
Hide file tree
Showing 15 changed files with 2,592 additions and 13,349 deletions.
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"extends": ["xo", "xo-typescript", "prettier", "prettier/@typescript-eslint"],
"rules": {
"capitalized-comments": 0,
"no-void": 0,
"@typescript-eslint/no-floating-promises": 0,
"@typescript-eslint/no-var-requires": 0,
"@typescript-eslint/no-implicit-any-catch": 0,
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
- run: npm i -g bower
- run: npm ci
- run: npm run static
- run: npm test
- run: npm run test-ci
- uses: codecov/codecov-action@v3
if: matrix.node-version == '22'
- run: npm run build
15,825 changes: 2,531 additions & 13,294 deletions package-lock.json

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
"fix": "run-s fix:*",
"fix:prettier": "prettier --write \"**/*.ts\"",
"fix:eslint": "eslint --fix \"**/*.ts\"",
"test": "jest --colors --coverage"
"test": "vitest",
"test-ci": "vitest run --coverage"
},
"prettier": "@gamesdonequick/prettier-config",
"dependencies": {
Expand All @@ -50,8 +51,7 @@
"@types/fs-extra": "5.0.4",
"@types/hosted-git-info": "2.7.0",
"@types/inquirer": "^7.3.1",
"@types/jest": "^26.0.14",
"@types/node": "16",
"@types/node": "18",
"@types/node-fetch": "^2.6.2",
"@types/npm-package-arg": "6.1.0",
"@types/rimraf": "2.0.2",
Expand All @@ -60,18 +60,18 @@
"@types/tmp": "^0.2.0",
"@typescript-eslint/eslint-plugin": "^4.4.0",
"@typescript-eslint/parser": "^4.4.0",
"@vitest/coverage-v8": "^2.1.8",
"coveralls": "^3.1.0",
"eslint": "^7.10.0",
"eslint-config-prettier": "^6.12.0",
"eslint-config-xo": "^0.32.1",
"eslint-config-xo-typescript": "^0.33.0",
"jest": "^26.4.2",
"npm-run-all": "^4.1.5",
"prettier": "^2.1.2",
"tmp": "0.2.1",
"ts-jest": "^26.4.1",
"type-fest": "^0.17.0",
"typescript": "4.2.3"
"typescript": "~5.7.2",
"vitest": "^2.1.8"
},
"engines": {
"node": "^18.12.0 || ^20.9.0 || ^22.11.0"
Expand Down
6 changes: 3 additions & 3 deletions src/commands/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ function action(repo: string, options: { dev: boolean }) {
range,
);
process.stdout.write(chalk.green('done!') + os.EOL);
} catch (e) {
} catch (e: any) {
/* istanbul ignore next */
process.stdout.write(chalk.red('failed!') + os.EOL);
/* istanbul ignore next */
Expand All @@ -89,7 +89,7 @@ function action(repo: string, options: { dev: boolean }) {
try {
execSync(`git clone ${repoUrl} "${bundlePath}"`, { stdio: ['pipe', 'pipe', 'pipe'] });
process.stdout.write(chalk.green('done!') + os.EOL);
} catch (e) {
} catch (e: any) {
/* istanbul ignore next */
process.stdout.write(chalk.red('failed!') + os.EOL);
/* istanbul ignore next */
Expand All @@ -116,7 +116,7 @@ function action(repo: string, options: { dev: boolean }) {
stdio: ['pipe', 'pipe', 'pipe'],
});
process.stdout.write(chalk.green('done!') + os.EOL);
} catch (e) {
} catch (e: any) {
/* istanbul ignore next */
process.stdout.write(chalk.red('failed!') + os.EOL);
/* istanbul ignore next */
Expand Down
8 changes: 4 additions & 4 deletions src/commands/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ async function decideActionVersion(version: string, options: { update: boolean;
let tags;
try {
tags = fetchTags(NODECG_GIT_URL);
} catch (e) {
} catch (e: any) {
/* istanbul ignore next */
process.stdout.write(chalk.red('failed!') + os.EOL);
/* istanbul ignore next */
Expand Down Expand Up @@ -214,7 +214,7 @@ function installDependencies() {
execSync('npm i --production', { stdio: ['pipe', 'pipe', 'pipe'] });

process.stdout.write(chalk.green('done!') + os.EOL);
} catch (e) {
} catch (e: any) {
process.stdout.write(chalk.red('failed!') + os.EOL);
console.error(e.stack);
return;
Expand All @@ -225,7 +225,7 @@ function installDependencies() {
try {
execSync('bower install --production', { stdio: ['pipe', 'pipe', 'pipe'] });
process.stdout.write(chalk.green('done!') + os.EOL);
} catch (e) {
} catch (e: any) {
process.stdout.write(chalk.red('failed!') + os.EOL);
console.error(e.stack);
}
Expand All @@ -236,7 +236,7 @@ function gitCheckoutUpdate(target: string) {
try {
execSync(`git checkout ${target}`, { stdio: ['pipe', 'pipe', 'pipe'] });
process.stdout.write(chalk.green('done!') + os.EOL);
} catch (e) {
} catch (e: any) {
/* istanbul ignore next */
process.stdout.write(chalk.red('failed!') + os.EOL);
/* istanbul ignore next */
Expand Down
2 changes: 1 addition & 1 deletion src/commands/uninstall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function deleteBundle(name: string, path: string) {
process.stdout.write('Uninstalling ' + chalk.magenta(name) + '... ');
try {
rimraf.sync(path);
} catch (e) {
} catch (e: any) {
/* istanbul ignore next */
process.stdout.write(chalk.red('failed!') + os.EOL);
/* istanbul ignore next */
Expand Down
4 changes: 2 additions & 2 deletions src/lib/install-bundle-deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export default function (bundlePath: string, installDev = false) {
stdio: ['pipe', 'pipe', 'pipe'],
});
process.stdout.write(chalk.green('done!') + os.EOL);
} catch (e) {
} catch (e: any) {
/* istanbul ignore next */
process.stdout.write(chalk.red('failed!') + os.EOL);
/* istanbul ignore next */
Expand All @@ -62,7 +62,7 @@ export default function (bundlePath: string, installDev = false) {
stdio: ['pipe', 'pipe', 'pipe'],
});
process.stdout.write(chalk.green('done!') + os.EOL);
} catch (e) {
} catch (e: any) {
/* istanbul ignore next */
process.stdout.write(chalk.red('failed!') + os.EOL);
/* istanbul ignore next */
Expand Down
17 changes: 9 additions & 8 deletions test/commands/defaultconfig.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import temp from 'tmp';
import { Command } from 'commander';
import { createMockProgram, MockCommand } from '../mocks/program';
import defaultConfigCommand from '../../src/commands/defaultconfig';
import { beforeEach, describe, expect, it, vi } from 'vitest';

let program: MockCommand;

Expand Down Expand Up @@ -32,26 +33,26 @@ describe('when run with a bundle argument', () => {
});

it('should print an error when the target bundle does not have a configschema.json', async () => {
const spy = jest.spyOn(console, 'error');
const spy = vi.spyOn(console, 'error');
fse.mkdirpSync(path.resolve(process.cwd(), './bundles/missing-schema-bundle'));
await program.runWith('defaultconfig missing-schema-bundle');
expect(spy.mock.calls[0][0]).toBe('\u001b[31mError:\u001b[39m Bundle %s does not have a configschema.json');
expect(spy.mock.calls[0][0]).toMatchInlineSnapshot(`"Error: Bundle %s does not have a configschema.json"`);
spy.mockRestore();
});

it('should print an error when the target bundle does not exist', async () => {
const spy = jest.spyOn(console, 'error');
const spy = vi.spyOn(console, 'error');
await program.runWith('defaultconfig not-installed');
expect(spy.mock.calls[0][0]).toBe('\u001b[31mError:\u001b[39m Bundle %s does not exist');
expect(spy.mock.calls[0][0]).toMatchInlineSnapshot(`"Error: Bundle %s does not exist"`);
spy.mockRestore();
});

it('should print an error when the target bundle already has a config', async () => {
const spy = jest.spyOn(console, 'error');
const spy = vi.spyOn(console, 'error');
fs.mkdirSync('./cfg');
fs.writeFileSync('./cfg/config-schema.json', JSON.stringify({ fake: 'data' }));
await program.runWith('defaultconfig config-schema');
expect(spy.mock.calls[0][0]).toBe('\u001b[31mError:\u001b[39m Bundle %s already has a config file');
expect(spy.mock.calls[0][0]).toMatchInlineSnapshot(`"Error: Bundle %s already has a config file"`);
spy.mockRestore();
});
});
Expand All @@ -67,9 +68,9 @@ describe('when run with no arguments', () => {
fse.mkdirpSync(path.resolve(process.cwd(), './bundles/not-a-bundle'));
process.chdir('./bundles/not-a-bundle');

const spy = jest.spyOn(console, 'error');
const spy = vi.spyOn(console, 'error');
await program.runWith('defaultconfig');
expect(spy.mock.calls[0][0]).toBe('\u001b[31mError:\u001b[39m No bundle found in the current directory!');
expect(spy.mock.calls[0][0]).toMatchInlineSnapshot(`"Error: No bundle found in the current directory!"`);
spy.mockRestore();
});
});
3 changes: 2 additions & 1 deletion test/commands/install.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import temp from 'tmp';
import { createMockProgram, MockCommand } from '../mocks/program';
import installCommand from '../../src/commands/install';
import { Command } from 'commander';
import { beforeEach, expect, it, vi } from 'vitest';

let program: MockCommand;
const tempFolder = temp.dirSync();
Expand Down Expand Up @@ -46,7 +47,7 @@ it('should install bower & npm dependencies when run with no arguments in a bund
});

it('should print an error when no valid git repo is provided', async () => {
const spy = jest.spyOn(console, 'error');
const spy = vi.spyOn(console, 'error');
await program.runWith('install 123');
expect(spy).toBeCalledWith('Please enter a valid git repository URL or GitHub username/repo pair.');
spy.mockRestore();
Expand Down
24 changes: 13 additions & 11 deletions test/commands/schema-types.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import temp from 'tmp';
import { MockCommand, createMockProgram } from '../mocks/program';
import schemaTypesCommand from '../../src/commands/schema-types';
import { EventEmitter } from 'events';
import { beforeEach, expect, it, vi } from 'vitest';

let program: MockCommand;

Expand Down Expand Up @@ -42,20 +43,18 @@ it('should successfully create d.ts files from the replicant schemas and create
const outputPath = './src/types/schemas/example.d.ts';
expect(fs.existsSync(outputPath)).toBe(true);

expect(fs.readFileSync(outputPath, 'utf8')).toBe(
fs.readFileSync('../../results/schema-types/example.d.ts', 'utf8'),
);
expect(fs.readFileSync(outputPath, 'utf8')).toMatchFileSnapshot('../fixtures/results/schema-types/example.d.ts');

const indexPath = './src/types/schemas/index.d.ts';
expect(fs.existsSync(indexPath)).toBe(true);
expect(fs.readFileSync(indexPath, 'utf8')).toBe(fs.readFileSync('../../results/schema-types/index.d.ts', 'utf8'));
expect(fs.readFileSync(indexPath, 'utf8')).toMatchFileSnapshot('../fixtures/results/schema-types/index.d.ts');
});

it('should print an error when the target bundle does not have a schemas dir', async () => {
process.chdir('bundles/uninstall-test');
const spy = jest.spyOn(console, 'error');
const spy = vi.spyOn(console, 'error');
await program.runWith('schema-types');
expect(spy.mock.calls[0][0]).toBe('\u001b[31mError:\u001b[39m Input directory ("%s") does not exist');
expect(spy.mock.calls[0][0]).toMatchInlineSnapshot(`"Error: Input directory ("%s") does not exist"`);
spy.mockRestore();
});

Expand All @@ -68,12 +67,15 @@ it('should successfully compile the config schema', async () => {
const outputPath = './src/types/schemas/configschema.d.ts';
expect(fs.existsSync(outputPath)).toBe(true);

expect(fs.readFileSync(outputPath, 'utf8')).toBe(
fs.readFileSync('../../results/schema-types/configschema.d.ts', 'utf8'),
);
expect(fs.readFileSync('./src/types/schemas/index.d.ts', 'utf8')).toBe(
"/* eslint-disable */\n// @ts-ignore\nexport * from './configschema';\n",
expect(fs.readFileSync(outputPath, 'utf8')).toMatchFileSnapshot(
'../fixtures/results/schema-types/configschema.d.ts',
);
expect(fs.readFileSync('./src/types/schemas/index.d.ts', 'utf8')).toMatchInlineSnapshot(`
"/* eslint-disable */
// @ts-ignore
export * from './configschema';
"
`);
});

async function waitForEvent(emitter: EventEmitter, eventName: string) {
Expand Down
25 changes: 14 additions & 11 deletions test/commands/setup.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { PackageJson } from 'type-fest';
import { Command } from 'commander';
import { createMockProgram, MockCommand } from '../mocks/program';
import setupCommand from '../../src/commands/setup';
import { beforeEach, expect, test, vi } from 'vitest';

let program: MockCommand;
let currentDir = temp.dirSync();
Expand Down Expand Up @@ -47,7 +48,7 @@ test('should install v1 NodeCG when specified', async () => {
});

test('should ask the user for confirmation when downgrading versions', async () => {
const spy = jest.spyOn(inquirer, 'prompt').mockReturnValue(Promise.resolve({ installOlder: true }) as any);
const spy = vi.spyOn(inquirer, 'prompt').mockReturnValue(Promise.resolve({ installOlder: true }) as any);
await program.runWith('setup 0.8.1 -u --skip-dependencies');
expect(spy).toBeCalled();
expect(readPackageJson().version).toBe('0.8.1');
Expand All @@ -60,34 +61,36 @@ test('should let the user change upgrade versions', async () => {
});

test('should print an error when the target version is the same as current', async () => {
const spy = jest.spyOn(console, 'log');
const spy = vi.spyOn(console, 'log');
await program.runWith('setup 0.8.2 -u --skip-dependencies');
expect(spy).toBeCalledWith(
'The target version (%s) is equal to the current version (%s). No action will be taken.',
'\u001b[35mv0.8.2\u001b[39m',
'\u001b[35m0.8.2\u001b[39m',
);
expect(spy.mock.calls[0]).toMatchInlineSnapshot(`
[
"The target version (%s) is equal to the current version (%s). No action will be taken.",
"v0.8.2",
"0.8.2",
]
`);
spy.mockRestore();
});

test('should correctly handle and refuse when you try to downgrade from v2 to v1', async () => {
chdir();
jest.spyOn(inquirer, 'prompt').mockReturnValue(Promise.resolve({ installOlder: true }) as any);
vi.spyOn(inquirer, 'prompt').mockReturnValue(Promise.resolve({ installOlder: true }) as any);
await program.runWith('setup 2.0.0 --skip-dependencies');
expect(readPackageJson().version).toBe('2.0.0');
await program.runWith('setup 1.9.0 -u --skip-dependencies');
expect(readPackageJson().version).toBe('2.0.0');
});

test("should print an error when the target version doesn't exist", async () => {
const spy = jest.spyOn(console, 'error');
const spy = vi.spyOn(console, 'error');
await program.runWith('setup 0.0.99 -u --skip-dependencies');
expect(spy).toBeCalledWith('No releases match the supplied semver range (\u001b[35m0.0.99\u001b[39m)');
expect(spy.mock.calls[0][0]).toMatchInlineSnapshot(`"No releases match the supplied semver range (0.0.99)"`);
spy.mockRestore();
});

test('should print an error and exit, when nodecg is already installed in the current directory ', async () => {
const spy = jest.spyOn(console, 'error');
const spy = vi.spyOn(console, 'error');
await program.runWith('setup 0.7.0 --skip-dependencies');
expect(spy).toBeCalledWith('NodeCG is already installed in this directory.');
spy.mockRestore();
Expand Down
5 changes: 3 additions & 2 deletions test/commands/uninstall.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import fse from 'fs-extra';
import { Command } from 'commander';
import { MockCommand, createMockProgram } from '../mocks/program';
import uninstallCommand from '../../src/commands/uninstall';
import { beforeEach, expect, it, vi } from 'vitest';

let program: MockCommand;

Expand All @@ -24,7 +25,7 @@ beforeEach(() => {
});

it("should delete the bundle's folder after prompting for confirmation", async () => {
const spy = jest.spyOn(inquirer, 'prompt').mockImplementation(() => {
const spy = vi.spyOn(inquirer, 'prompt').mockImplementation(() => {
return Promise.resolve({ confirmUninstall: true }) as any;
});
await program.runWith('uninstall uninstall-test');
Expand All @@ -33,7 +34,7 @@ it("should delete the bundle's folder after prompting for confirmation", async (
});

it('should print an error when the target bundle is not installed', async () => {
const spy = jest.spyOn(console, 'error');
const spy = vi.spyOn(console, 'error');
await program.runWith('uninstall not-installed');
expect(spy.mock.calls[0][0]).toBe('Cannot uninstall %s: bundle is not installed.');
spy.mockRestore();
Expand Down
3 changes: 0 additions & 3 deletions test/mocha.opts

This file was deleted.

4 changes: 2 additions & 2 deletions test/mocks/program.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { mock } from 'node:test';
import commander from 'commander';

export class MockCommand extends commander.Command {
Expand All @@ -17,8 +18,7 @@ export class MockCommand extends commander.Command {
export const createMockProgram = () => {
const program = new MockCommand();

// eslint-disable-next-line no-void
jest.spyOn(program, 'log').mockReturnValue(void 0);
mock.method(program, 'log').mock.mockImplementation(() => void 0);

return program;
};

0 comments on commit d3771a6

Please sign in to comment.