Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: replace jest with vitest #101

Merged
merged 13 commits into from
Dec 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
};
Loading