Skip to content
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
12 changes: 12 additions & 0 deletions .changeset/dependabot-update-12355.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
"miniflare": patch
"wrangler": patch
---

Update dependencies of "miniflare", "wrangler"

The following dependency versions have been updated:

| Dependency | From | To |
| ---------- | ------------ | ------------ |
| workerd | 1.20260130.0 | 1.20260131.0 |
8 changes: 8 additions & 0 deletions .changeset/real-teeth-obey.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@cloudflare/eslint-config-shared": patch
---

Add an ESLint rule checking that `expect` is not imported from `vitest`.

Retrieving `expect` from the test context is safer for concurrent tests,
so we will standardize on using that.
52 changes: 32 additions & 20 deletions packages/cli/__tests__/check-macos-version.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import os from "node:os";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { beforeEach, describe, it, vi } from "vitest";
import { checkMacOSVersion } from "../check-macos-version";

vi.mock("node:os");
Expand All @@ -12,34 +12,34 @@ describe("checkMacOSVersion", () => {
vi.unstubAllEnvs();
});

it("should not throw on non-macOS platforms", () => {
it("should not throw on non-macOS platforms", ({ expect }) => {
vi.spyOn(process, "platform", "get").mockReturnValue("linux");

expect(() => checkMacOSVersion({ shouldThrow: true })).not.toThrow();
});

it("should not throw on macOS 13.5.0", () => {
it("should not throw on macOS 13.5.0", ({ expect }) => {
vi.spyOn(process, "platform", "get").mockReturnValue("darwin");
mockOs.release.mockReturnValue("22.6.0");

expect(() => checkMacOSVersion({ shouldThrow: true })).not.toThrow();
});

it("should not throw on macOS 14.0.0", () => {
it("should not throw on macOS 14.0.0", ({ expect }) => {
vi.spyOn(process, "platform", "get").mockReturnValue("darwin");
mockOs.release.mockReturnValue("23.0.0");

expect(() => checkMacOSVersion({ shouldThrow: true })).not.toThrow();
});

it("should not throw on macOS 13.6.0", () => {
it("should not throw on macOS 13.6.0", ({ expect }) => {
vi.spyOn(process, "platform", "get").mockReturnValue("darwin");
mockOs.release.mockReturnValue("22.7.0");

expect(() => checkMacOSVersion({ shouldThrow: true })).not.toThrow();
});

it("should throw error on macOS 12.7.6", () => {
it("should throw error on macOS 12.7.6", ({ expect }) => {
vi.spyOn(process, "platform", "get").mockReturnValue("darwin");
vi.stubEnv("CI", "");
mockOs.release.mockReturnValue("21.6.0");
Expand All @@ -49,7 +49,7 @@ describe("checkMacOSVersion", () => {
);
});

it("should throw error on macOS 13.4.0", () => {
it("should throw error on macOS 13.4.0", ({ expect }) => {
vi.spyOn(process, "platform", "get").mockReturnValue("darwin");
vi.stubEnv("CI", "");
mockOs.release.mockReturnValue("22.4.0");
Expand All @@ -59,37 +59,43 @@ describe("checkMacOSVersion", () => {
);
});

it("should handle invalid Darwin version format gracefully", () => {
it("should handle invalid Darwin version format gracefully", ({ expect }) => {
vi.spyOn(process, "platform", "get").mockReturnValue("darwin");
mockOs.release.mockReturnValue("invalid-version");

expect(() => checkMacOSVersion({ shouldThrow: true })).not.toThrow();
});

it("should handle very old Darwin versions gracefully", () => {
it("should handle very old Darwin versions gracefully", ({ expect }) => {
vi.spyOn(process, "platform", "get").mockReturnValue("darwin");
mockOs.release.mockReturnValue("19.6.0");

expect(() => checkMacOSVersion({ shouldThrow: true })).not.toThrow();
});

it("should not throw when CI environment variable is set to 'true'", () => {
it("should not throw when CI environment variable is set to 'true'", ({
expect,
}) => {
vi.spyOn(process, "platform", "get").mockReturnValue("darwin");
vi.stubEnv("CI", "true");
mockOs.release.mockReturnValue("21.6.0");

expect(() => checkMacOSVersion({ shouldThrow: true })).not.toThrow();
});

it("should not throw when CI environment variable is set to '1'", () => {
it("should not throw when CI environment variable is set to '1'", ({
expect,
}) => {
vi.spyOn(process, "platform", "get").mockReturnValue("darwin");
vi.stubEnv("CI", "1");
mockOs.release.mockReturnValue("21.6.0");

expect(() => checkMacOSVersion({ shouldThrow: true })).not.toThrow();
});

it("should not throw when CI environment variable is set to 'yes'", () => {
it("should not throw when CI environment variable is set to 'yes'", ({
expect,
}) => {
vi.spyOn(process, "platform", "get").mockReturnValue("darwin");
vi.stubEnv("CI", "yes");
mockOs.release.mockReturnValue("21.6.0");
Expand All @@ -104,7 +110,7 @@ describe("checkMacOSVersion with shouldThrow=false", () => {
vi.unstubAllEnvs();
});

it("should not warn on non-macOS platforms", () => {
it("should not warn on non-macOS platforms", ({ expect }) => {
vi.spyOn(process, "platform", "get").mockReturnValue("linux");
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});

Expand All @@ -113,7 +119,7 @@ describe("checkMacOSVersion with shouldThrow=false", () => {
expect(warnSpy).not.toHaveBeenCalled();
});

it("should not warn on macOS 13.5.0", () => {
it("should not warn on macOS 13.5.0", ({ expect }) => {
vi.spyOn(process, "platform", "get").mockReturnValue("darwin");
mockOs.release.mockReturnValue("22.6.0");
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
Expand All @@ -123,7 +129,7 @@ describe("checkMacOSVersion with shouldThrow=false", () => {
expect(warnSpy).not.toHaveBeenCalled();
});

it("should warn on macOS 12.7.6", () => {
it("should warn on macOS 12.7.6", ({ expect }) => {
vi.spyOn(process, "platform", "get").mockReturnValue("darwin");
vi.stubEnv("CI", "");
mockOs.release.mockReturnValue("21.6.0");
Expand All @@ -138,7 +144,7 @@ describe("checkMacOSVersion with shouldThrow=false", () => {
);
});

it("should warn on macOS 13.4.0", () => {
it("should warn on macOS 13.4.0", ({ expect }) => {
vi.spyOn(process, "platform", "get").mockReturnValue("darwin");
vi.stubEnv("CI", "");
mockOs.release.mockReturnValue("22.4.0");
Expand All @@ -153,7 +159,9 @@ describe("checkMacOSVersion with shouldThrow=false", () => {
);
});

it("should not warn when CI environment variable is set to 'true'", () => {
it("should not warn when CI environment variable is set to 'true'", ({
expect,
}) => {
vi.spyOn(process, "platform", "get").mockReturnValue("darwin");
vi.stubEnv("CI", "true");
mockOs.release.mockReturnValue("21.6.0");
Expand All @@ -164,7 +172,9 @@ describe("checkMacOSVersion with shouldThrow=false", () => {
expect(warnSpy).not.toHaveBeenCalled();
});

it("should not warn when CI environment variable is set to '1'", () => {
it("should not warn when CI environment variable is set to '1'", ({
expect,
}) => {
vi.spyOn(process, "platform", "get").mockReturnValue("darwin");
vi.stubEnv("CI", "1");
mockOs.release.mockReturnValue("21.6.0");
Expand All @@ -175,7 +185,9 @@ describe("checkMacOSVersion with shouldThrow=false", () => {
expect(warnSpy).not.toHaveBeenCalled();
});

it("should not warn when CI environment variable is set to 'yes'", () => {
it("should not warn when CI environment variable is set to 'yes'", ({
expect,
}) => {
vi.spyOn(process, "platform", "get").mockReturnValue("darwin");
vi.stubEnv("CI", "yes");
mockOs.release.mockReturnValue("21.6.0");
Expand All @@ -186,7 +198,7 @@ describe("checkMacOSVersion with shouldThrow=false", () => {
expect(warnSpy).not.toHaveBeenCalled();
});

it("should not warn on invalid Darwin version format", () => {
it("should not warn on invalid Darwin version format", ({ expect }) => {
vi.spyOn(process, "platform", "get").mockReturnValue("darwin");
mockOs.release.mockReturnValue("invalid-version");
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/__tests__/cli.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { describe, expect, test } from "vitest";
import { describe, test } from "vitest";
import { space } from "..";

describe("cli", () => {
test("test spaces", () => {
test("test spaces", ({ expect }) => {
expect(space(300)).toMatchInlineSnapshot(
'"                                                                                                                                                                                                                                                                                                            "'
);
Expand Down
19 changes: 14 additions & 5 deletions packages/cli/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import sharedConfig from "@cloudflare/eslint-config-shared";
import { defineConfig } from "eslint/config";

export default defineConfig({
extends: [sharedConfig],
rules: {
"no-console": "error",
export default defineConfig([
{
extends: [sharedConfig],
rules: {
"no-console": "error",
},
},
});
// Enable no-vitest-import-expect for test files
{
files: ["**/*.test.ts", "**/*.spec.ts", "**/__tests__/**/*.ts"],
rules: {
"workers-sdk/no-vitest-import-expect": "error",
},
},
]);
2 changes: 2 additions & 0 deletions packages/eslint-config-shared/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import unusedImports from "eslint-plugin-unused-imports";
import { defineConfig, globalIgnores } from "eslint/config";
import tseslint from "typescript-eslint";
import noUnsafeCommandExecution from "./rules/no-unsafe-command-execution.mjs";
import noVitestImportExpect from "./rules/no-vitest-import-expect.mjs";

export default defineConfig(
globalIgnores([
Expand Down Expand Up @@ -34,6 +35,7 @@ export default defineConfig(
"workers-sdk": {
rules: {
"no-unsafe-command-execution": noUnsafeCommandExecution,
"no-vitest-import-expect": noVitestImportExpect,
},
},
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { RuleTester } from "eslint";
import rule from "../no-vitest-import-expect.mjs";

const ruleTester = new RuleTester({
languageOptions: { ecmaVersion: 2022, sourceType: "module" },
});

ruleTester.run("no-vitest-import-expect", rule, {
valid: [
// No expect import from vitest
{
code: 'import { test, describe, it } from "vitest";',
},
// Import expect from other packages is allowed
{
code: 'import { expect } from "chai";',
},
{
code: 'import { expect } from "@jest/globals";',
},
// Default import from vitest is allowed
{
code: 'import vitest from "vitest";',
},
// Namespace import from vitest is allowed
{
code: 'import * as vitest from "vitest";',
},
// Other named imports from vitest are allowed
{
code: 'import { vi, describe, it, test, beforeEach, afterEach } from "vitest";',
},
],

invalid: [
// Direct expect import from vitest
{
code: 'import { expect } from "vitest";',
errors: [
{
messageId: "noVitestImportExpect",
},
],
},
// expect with other imports from vitest
{
code: 'import { expect, test, describe } from "vitest";',
errors: [
{
messageId: "noVitestImportExpect",
},
],
},
// expect at end of import list
{
code: 'import { test, describe, it, expect } from "vitest";',
errors: [
{
messageId: "noVitestImportExpect",
},
],
},
// Aliased expect import
{
code: 'import { expect as exp } from "vitest";',
errors: [
{
messageId: "noVitestImportExpect",
},
],
},
// expect with many other imports
{
code: 'import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";',
errors: [
{
messageId: "noVitestImportExpect",
},
],
},
],
});
58 changes: 58 additions & 0 deletions packages/eslint-config-shared/rules/no-vitest-import-expect.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* ESLint rule to disallow importing `expect` from vitest.
*
* When running tests concurrently, the global `expect` cannot reliably detect
* which test is running. Instead, `expect` should be destructured from the
* test context: test("name", ({ expect }) => { ... })
*
* @see https://vitest.dev/guide/features.html#running-tests-concurrently
*/

export default {
meta: {
type: "problem",
docs: {
description: "Disallow importing `expect` from vitest",
category: "Best Practices",
recommended: false,
url: "https://vitest.dev/guide/features.html#running-tests-concurrently",
},
messages: {
noVitestImportExpect:
"Import 'expect' from the test context instead of 'vitest' for concurrency safety. Use: test('name', ({ expect }) => { ... })",
},
schema: [],
},

create(context) {
return {
ImportDeclaration(node) {
// Only check imports from "vitest"
if (node.source.value !== "vitest") {
return;
}

// Check each import specifier
for (const specifier of node.specifiers) {
// Only check named imports (import { expect } from "vitest")
if (specifier.type !== "ImportSpecifier") {
continue;
}

// Check if the imported name is "expect"
const importedName =
specifier.imported.type === "Identifier"
? specifier.imported.name
: specifier.imported.value;

if (importedName === "expect") {
context.report({
node: specifier,
messageId: "noVitestImportExpect",
});
}
}
},
};
},
};
Loading
Loading