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: remove remaining vestiges of jest types #4435

Merged
merged 17 commits into from
Aug 7, 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
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ yarn dev

### Unit Testing LWC

When developing LWC, utilize [jest](https://jestjs.io/en/) unit testing to provide test coverage for new functionality. To run the jest tests use the following command from the root directory:
When developing LWC, utilize [vitest](https://vitest.dev/) unit testing to provide test coverage for new functionality. To run the vitest tests use the following command from the root directory:

```bash
yarn test
Expand Down Expand Up @@ -84,11 +84,11 @@ If you want to debug these tests, you can do as follow:
3. Click on "Open dedicated DevTools for Node"
4. In your terminal, type the following command: `yarn test:debug <path_to_test>`

Your test should now be running in the Chrome debugger which you can use to poke around and explore. Now simply hit Enter in the terminal running your Jest process anytime you want to re-run your currently selected specs. You'll be dropped right back into the Chrome debugger.
Your test should now be running in the Chrome debugger which you can use to poke around and explore. Now simply hit Enter in the terminal running your Vitest process anytime you want to re-run your currently selected specs. You'll be dropped right back into the Chrome debugger.

### Debugging Test Fixtures LWC

Test fixtures are file-based tests that are executed using a helper called [`testFixtureDir`](./scripts/jest/utils/test-fixture-dir.ts). Because this helper does not list tests individually, jest's [`test.only`](https://jestjs.io/docs/api#testonlyname-fn-timeout) and [`test.skip`](https://jestjs.io/docs/api#testskipname-fn) cannot be used. Instead, to achieve the same behavior, "directive" files can be added to individual test fixtures. If a file called `.only` is found in a test fixture, that test will use `test.only`. Similarly, if a file called `.skip` is found, `test.skip` will be used.
Test fixtures are file-based tests that are executed using a helper called [`testFixtureDir`](./scripts/test-utils/test-fixture-dir.ts). Because this helper does not list tests individually, vitest's [`test.only`](https://vitest.dev/api/#test-only) and [`test.skip`](https://vitest.dev/api/#test-skip) cannot be used. Instead, to achieve the same behavior, "directive" files can be added to individual test fixtures. If a file called `.only` is found in a test fixture, that test will use `test.only`. Similarly, if a file called `.skip` is found, `test.skip` will be used.

### Integration Testing LWC

Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"release:version": "./scripts/release/version.js"
},
"//": {
"prettier": "v3 requires ESM, and we use prettier in our Jest tests. Jest does not support ESM yet."
"prettier": "Outdated since Jest has been replaced with vitest: v3 requires ESM, and we use prettier in our Jest tests. Jest does not support ESM yet."
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a reminder here, maybe for another PR? I reckon this is related to #4386

},
"devDependencies": {
"@commitlint/cli": "^19.3.0",
Expand All @@ -48,7 +48,9 @@
"@types/node": "^22.1.0",
"@types/prettier": "^2.7.3",
"@vitest/coverage-v8": "^2.0.5",
"@vitest/expect": "^2.0.5",
"@vitest/ui": "^2.0.5",
"@vitest/utils": "^2.0.5",
"bytes": "^3.1.2",
"es-module-lexer": "^1.5.4",
"eslint": "^9.8.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/@lwc/engine-core/src/shared/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ function log(method: 'warn' | 'error', message: string, vm: VM | undefined, once
alreadyLoggedMessages.add(msg);
}

// In Jest tests, reduce the warning and error verbosity by not printing the callstack
// In Vitest tests, reduce the warning and error verbosity by not printing the callstack
if (process.env.NODE_ENV === 'test') {
/* eslint-disable-next-line no-console */
console[method](msg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/

import { renderComponent, LightningElement } from '../index';

class Test extends LightningElement {}
Expand Down
25 changes: 10 additions & 15 deletions packages/@lwc/errors/src/__tests__/errors.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,18 @@ const ERROR_CODE_RANGES = {
},
};

declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace jest {
interface Matchers<R> {
__type: R; // unused, but makes TypeScript happy
toBeUniqueCode: (key: string, seenErrorCodes: Set<number>) => object;
toBeInRange: (min: number, max: number, key: string) => object;
}
}
interface CustomMatchers<R = unknown> {
toBeUniqueCode: (key: string, seenErrorCodes: Set<number>) => R;
toBeInRange: (range: { min: number; max: number }, key: string) => R;
}

declare module 'vitest' {
interface Assertion<T = any> extends CustomMatchers<T> {}
interface AsymmetricMatchersContaining extends CustomMatchers {}
}

expect.extend({
toBeInRange(code, min, max, key) {
toBeInRange(code, { min, max }, key) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typing will only work here if there's no more than 3 parameters, although tests would pass. VSCode shows errors otherwise.

const pass = Number.isInteger(code) && code >= min && code <= max;
const message = () =>
`expected ${key}'s error code '${code}'${
Expand Down Expand Up @@ -68,11 +67,7 @@ function traverseErrorInfo(
describe('error validation', () => {
it('compiler error codes are in the correct range', () => {
function validate(errorInfo: LWCErrorInfo, key: string) {
expect(errorInfo.code).toBeInRange(
ERROR_CODE_RANGES.compiler.min,
ERROR_CODE_RANGES.compiler.max,
key
);
expect(errorInfo.code).toBeInRange(ERROR_CODE_RANGES.compiler, key);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice

}

traverseErrorInfo(CompilerErrors, validate, 'compiler');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
import * as errorInfo from '../error-info';

// All exported objects are maps of label/error info, except for GENERIC_COMPILER_ERROR,
// which is a top-level error info object
const { GENERIC_COMPILER_ERROR, ...errors } = errorInfo;
Expand All @@ -14,7 +13,7 @@ const errorInfoMatcher = {
code: expect.any(Number),
message: expect.any(String),
url: expect.any(String),
// Technically not *any* number, but jest doesn't have oneOf
// Technically not *any* number, but vitest doesn't have oneOf
level: expect.any(Number),
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/

import diff from 'jest-diff';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was getting pulled in by @wdio/cli! Whoops 🫣

import MatcherUtils = jest.MatcherUtils;
import diff from '@vitest/utils/diff';
import type { MatcherState } from '@vitest/expect';
Copy link
Collaborator

@nolanlawson nolanlawson Aug 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These packages both already come from vitest, but it makes me nervous not to have these explicitly declared in the root package.json. Let's add them.


export function toThrowErrorWithCode(
this: MatcherUtils,
this: MatcherState,
received: any,
code: string,
message?: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/

import diff from 'jest-diff';
import MatcherUtils = jest.MatcherUtils;
import diff from '@vitest/utils/diff';
import type { MatcherState } from '@vitest/expect';

export function toThrowErrorWithType(
this: MatcherUtils,
this: MatcherState,
received: any,
ctor: any,
message?: string
Expand Down
20 changes: 10 additions & 10 deletions packages/@lwc/module-resolver/scripts/test/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
export {}; // required to have a module with just `declare global` in it
/// <reference types="vitest/globals" />
import 'vitest';

declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace jest {
interface Matchers<R> {
__type: R; // unused, but makes TypeScript happy
toThrowErrorWithCode(received: any, ctor: any, message?: string): CustomMatcherResult;
toThrowErrorWithType(received: any, ctor: any, message?: string): CustomMatcherResult;
}
}
interface CustomMatchers<R = unknown> {
toThrowErrorWithCode: (received: any, ctor: any, message?: string) => R;
toThrowErrorWithType: (received: any, ctor: any, message?: string) => R;
}

declare module 'vitest' {
interface Assertion<T = any> extends CustomMatchers<T> {}
interface AsymmetricMatchersContaining extends CustomMatchers {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('customRendererConfig normalization', () => {
},
});
expect(normalizedConfig.apiVersion).toBe(HIGHEST_API_VERSION);
normalizedConfig.apiVersion = -1; // avoid testing in inline snapshot so that Jest can easily update it
normalizedConfig.apiVersion = -1; // avoid testing in inline snapshot so that vitest can easily update it

expect(normalizedConfig).toMatchInlineSnapshot(`
{
Expand Down
2 changes: 2 additions & 0 deletions packages/lwc/__tests__/default-exports.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const expectExportDefaultFromPackageInFile = (pkgName: string, ext: string) => {
};

/*
* This comment needs to be updated:
* Jest uses CommonJS, which means that packages with no explicit export statements actually export
* the default `module.exports` empty object. That export is an empty object with the prototype set
* to an empty object with null prototype.
cardoso marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -59,6 +60,7 @@ describe('default exports are not forgotten', () => {
'dist/index.js'
);
const realModule = await import(pathToEsmDistFile);
// The commend below needs to be updated:
// When jest properly supports ESM, this will be a lot simpler
// const aliasedModule = await import(`lwc/${pkg}`);
// expect(aliasedModule.default).toBe(realModule.default);
Comment on lines 62 to 66
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment and related code should be updated

Expand Down
2 changes: 1 addition & 1 deletion scripts/test-utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
import './matchers'; // File has no exports, but registers jest matchers
import './matchers'; // File has no exports, but registers vitest matchers
export * from './test-fixture-dir';
export * from './format-html';
43 changes: 21 additions & 22 deletions scripts/test-utils/matchers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,16 @@
*/

import fs from 'fs';
import MatcherUtils = jest.MatcherUtils;
import CustomMatcherResult = jest.CustomMatcherResult;
import type { MatcherState } from '@vitest/expect';

/**
* Jest matcher to assert that the content received matches the content in fixture file.
* Vitest matcher to assert that the content received matches the content in fixture file.
* @param receivedContent the fixture content
* @param filename the fixture absolute path
* @returns matcher result
* @example expect(content).toMatchFile(outputPath)
*/
function toMatchFile(
this: MatcherUtils,
receivedContent: string,
filename: string
): CustomMatcherResult {
function toMatchFile(this: MatcherState, receivedContent: string, filename: string) {
const { snapshotState, expand, utils } = this;

const fileExists = fs.existsSync(filename);
Expand All @@ -29,10 +24,10 @@ function toMatchFile(
const expectedContent = fs.readFileSync(filename, 'utf-8');

if (receivedContent === null || receivedContent === undefined) {
// If the file exists but the expected content is undefined or null. If the Jest is
// If the file exists but the expected content is undefined or null. If Vitest is
// running with the update snapshot flag the file should be deleted. Otherwise fails
// the assertion stating that the file is not expected to be there.
if (snapshotState._updateSnapshot === 'all') {
if (snapshotState['_updateSnapshot'] === 'all') {
fs.unlinkSync(filename);

snapshotState.updated++;
Expand All @@ -57,10 +52,10 @@ function toMatchFile(
// content everything is fine.
return { pass: true, message: () => '' };
} else {
// If the expected file is present but the content is not matching. if Jest is running
// If the expected file is present but the content is not matching. if Vitest is running
// with the update snapshot flag override the expected content. Otherwise fails the
// assertion with a diff.
if (snapshotState._updateSnapshot === 'all') {
if (snapshotState['_updateSnapshot'] === 'all') {
fs.writeFileSync(filename, receivedContent);

snapshotState.updated++;
Expand Down Expand Up @@ -93,7 +88,10 @@ function toMatchFile(

// If expected file doesn't exists but got a received content and if the snapshots
// should be updated, create the new snapshot. Otherwise fails the assertion.
if (snapshotState._updateSnapshot === 'new' || snapshotState._updateSnapshot === 'all') {
if (
snapshotState['_updateSnapshot'] === 'new' ||
snapshotState['_updateSnapshot'] === 'all'
) {
Comment on lines +91 to +94
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_updateSnapshot is private in vitest which means there's probably a better way to do this, but for now this is needed to avoid annoying errors in vscode.

fs.writeFileSync(filename, receivedContent);

snapshotState.added++;
Expand All @@ -113,15 +111,16 @@ function toMatchFile(
}
}

declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace jest {
interface Matchers<R> {
__type: R; // unused, but makes TypeScript happy
toMatchFile(receivedContent: string, filename?: string): CustomMatcherResult;
}
}
import 'vitest';

interface CustomMatchers<R = unknown> {
toMatchFile: (receivedContent: string, filename?: string) => R;
}

declare module 'vitest' {
interface Assertion<T = any> extends CustomMatchers<T> {}
interface AsymmetricMatchersContaining extends CustomMatchers {}
Comment on lines +114 to +122
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might fit better in a .d.ts file

}

// Register jest matcher.
// Register vitest matcher.
expect.extend({ toMatchFile });
4 changes: 2 additions & 2 deletions scripts/test-utils/test-fixture-dir.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ const { globSync } = glob;
type TestFixtureOutput = { [filename: string]: unknown };

/**
* Facilitates the use of jest's `test.only`/`test.skip` in fixture files.
* Facilitates the use of vitest's `test.only`/`test.skip` in fixture files.
* @param dirname fixture directory to check for "directive" files
* @returns `test.only` if `.only` exists, `test.skip` if `.skip` exists, otherwise `test`
* @throws if you have both `.only` and `.skip` in the directory
* @example getTestFunc('/fixtures/some-test')
*/
function getTestFunc(dirname: string): jest.It {
function getTestFunc(dirname: string) {
const isOnly = fs.existsSync(path.join(dirname, '.only'));
const isSkip = fs.existsSync(path.join(dirname, '.skip'));
if (isOnly && isSkip) {
Expand Down
6 changes: 4 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1015,9 +1015,11 @@

"@lwc/eslint-plugin-lwc-internal@link:./scripts/eslint-plugin":
version "0.0.0"
uid ""

"@lwc/test-utils-lwc-internals@link:./scripts/test-utils":
version "0.0.0"
uid ""

"@napi-rs/[email protected]":
version "0.2.4"
Expand Down Expand Up @@ -1961,7 +1963,7 @@
test-exclude "^7.0.1"
tinyrainbow "^1.2.0"

"@vitest/[email protected]":
"@vitest/[email protected]", "@vitest/expect@^2.0.5":
version "2.0.5"
resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-2.0.5.tgz#f3745a6a2c18acbea4d39f5935e913f40d26fa86"
integrity sha512-yHZtwuP7JZivj65Gxoi8upUN2OzHTi3zVfjwdpu2WrvCZPLwsJ2Ey5ILIPccoW23dd/zQBlJ4/dhi7DWNyXCpA==
Expand Down Expand Up @@ -2024,7 +2026,7 @@
sirv "^2.0.4"
tinyrainbow "^1.2.0"

"@vitest/[email protected]":
"@vitest/[email protected]", "@vitest/utils@^2.0.5":
version "2.0.5"
resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-2.0.5.tgz#6f8307a4b6bc6ceb9270007f73c67c915944e926"
integrity sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ==
Expand Down
Loading