Skip to content

Commit

Permalink
[core-util] Migrate from mocha & karma to vitest (Azure#27551)
Browse files Browse the repository at this point in the history
### Packages impacted by this PR

`@azure/core-util`

### Describe the problem that is addressed by this PR

An experiment to migrate away from mocha and karma to vitest. This
eliminates the need for a browser bundle as vitest uses the test source
files directly.

I have also created a small plugin to avoid needing to add additional 
browser mappings for testing
  • Loading branch information
xirzec authored Dec 19, 2023
1 parent c0d51b6 commit ed4eda1
Show file tree
Hide file tree
Showing 24 changed files with 1,293 additions and 454 deletions.
1,456 changes: 1,081 additions & 375 deletions common/config/rush/pnpm-lock.yaml

Large diffs are not rendered by default.

57 changes: 57 additions & 0 deletions common/tools/vite-plugin-browser-test-map/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"name": "@azure-tools/vite-plugin-browser-test-map",
"version": "1.0.0",
"description": "A vite plugin for dynamically remapping browser replacement maps for tests",
"sdk-type": "utility",
"type": "module",
"private": true,
"keywords": [
"vite-plugin"
],
"author": "Microsoft Corporation",
"license": "MIT",
"homepage": "https://github.com/Azure/azure-sdk-for-js/tree/main/common/tools/vite-plugin-browser-test-map/",
"repository": {
"type": "git",
"url": "https://github.com/Azure/azure-sdk-for-js.git",
"directory": "common/tools/vite-plugin-browser-test-map"
},
"bugs": {
"url": "https://github.com/Azure/azure-sdk-for-js/issues"
},
"main": "dist/index.js",
"files": [
"dist/"
],
"scripts": {
"build": "tsc -p .",
"build:samples": "echo Skipped.",
"build:test": "tsc -p .",
"clean": "rimraf dist/",
"format": "prettier --write --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"./**/*.{ts,json,md}\"",
"check-format": "prettier --list-different --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"./**/*.{ts,json,md}\"",
"lint": "eslint src --ext .ts",
"pack": "npm pack 2>&1",
"prebuild": "npm run clean",
"integration-test:browser": "echo skipped",
"integration-test:node": "echo skipped",
"integration-test": "npm run integration-test:node && npm run integration-test:browser",
"unit-test:node": "echo skipped",
"unit-test:browser": "echo skipped",
"unit-test": "npm run unit-test:node && npm run unit-test:browser",
"test": "npm run clean && npm run build:test && npm run unit-test"
},
"engines": {
"node": ">=18.0.0"
},
"dependencies": {
"tslib": "^2.2.0"
},
"devDependencies": {
"@types/node": "^18.0.0",
"eslint": "^8.50.0",
"prettier": "^2.5.1",
"rimraf": "^3.0.0",
"typescript": "~5.2.0"
}
}
32 changes: 32 additions & 0 deletions common/tools/vite-plugin-browser-test-map/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

function hasPackageCache<T extends {}>(
obj: T
): obj is T & { packageCache: Map<string, { data: any }> } {
return "packageCache" in obj;
}

function rewriteDistPath(path: string): string {
return path.replace(/^\.\/dist-esm\/(\S+)\.js$/, function replacer(_match, path) {
return `./src/${path}`;
});
}

export default function browserTestMap() {
return {
name: "browser-test-config",
enforce: "pre",
configResolved: (config: {}) => {
if (hasPackageCache(config)) {
for (const { data } of config.packageCache.values()) {
if (data.browser) {
for (const [key, value] of Object.entries<string>(data.browser)) {
data.browser[rewriteDistPath(key)] = rewriteDistPath(value);
}
}
}
}
},
};
}
11 changes: 11 additions & 0 deletions common/tools/vite-plugin-browser-test-map/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "../../../tsconfig",
"compilerOptions": {
"target": "es2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./dist",
"declarationDir": "./types"
},
"include": ["src/**/*.ts"]
}
11 changes: 7 additions & 4 deletions rush.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* This is the main configuration file for Rush.
* For full documentation, please see https://rushjs.io
*/{
*/ {
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush.schema.json",
/**
* (Required) This specifies the version of the Rush engine to be used in this repo.
Expand Down Expand Up @@ -623,9 +623,7 @@
{
"packageName": "@azure/identity",
"projectFolder": "sdk/identity/identity",
"decoupledLocalDependencies": [
"@azure/keyvault-keys"
],
"decoupledLocalDependencies": ["@azure/keyvault-keys"],
"versionPolicyName": "client"
},
{
Expand Down Expand Up @@ -823,6 +821,11 @@
"projectFolder": "common/tools/eslint-plugin-azure-sdk-helper",
"versionPolicyName": "utility"
},
{
"packageName": "@azure-tools/vite-plugin-browser-test-map",
"projectFolder": "common/tools/vite-plugin-browser-test-map",
"versionPolicyName": "utility"
},
{
"packageName": "@azure-tools/test-recorder",
"projectFolder": "sdk/test-utils/recorder",
Expand Down
7 changes: 7 additions & 0 deletions sdk/core/core-util/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"plugins": ["@azure/azure-sdk"],
"extends": ["plugin:@azure/azure-sdk/azure-sdk-base"],
"rules": {
"@azure/azure-sdk/ts-package-json-module": "off"
}
}
2 changes: 1 addition & 1 deletion sdk/core/core-util/api-extractor.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
"mainEntryPointFilePath": "types/latest/src/index.d.ts",
"mainEntryPointFilePath": "types/latest/index.d.ts",
"docModel": {
"enabled": true
},
Expand Down
58 changes: 22 additions & 36 deletions sdk/core/core-util/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@
"description": "Core library for shared utility methods",
"sdk-type": "client",
"main": "dist/index.js",
"module": "dist-esm/src/index.js",
"module": "dist-esm/index.js",
"browser": {
"./dist-esm/src/sha256.js": "./dist-esm/src/sha256.browser.js",
"./dist-esm/src/uuidUtils.js": "./dist-esm/src/uuidUtils.browser.js",
"./dist-esm/src/bytesEncoding.js": "./dist-esm/src/bytesEncoding.browser.js"
"./dist-esm/sha256.js": "./dist-esm/sha256.browser.js",
"./dist-esm/uuidUtils.js": "./dist-esm/uuidUtils.browser.js",
"./dist-esm/bytesEncoding.js": "./dist-esm/bytesEncoding.browser.js"
},
"react-native": {
"./dist/index.js": "./dist-esm/src/index.js",
"./dist-esm/src/uuidUtils.js": "./dist-esm/src/uuidUtils.native.js"
"./dist/index.js": "./dist-esm/index.js",
"./dist-esm/uuidUtils.js": "./dist-esm/uuidUtils.native.js"
},
"types": "types/latest/core-util.d.ts",
"scripts": {
"build:samples": "echo Obsolete",
"build:test": "tsc -p . && dev-tool run bundle",
"build": "npm run clean && tsc -p . && dev-tool run bundle && api-extractor run --local",
"build:test": "npx playwright install",
"build": "npm run clean && tsc -p . && dev-tool run bundle --browser-test false && api-extractor run --local",
"check-format": "prettier --list-different --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"",
"clean": "rimraf dist dist-* temp types *.tgz *.log",
"execute:samples": "echo skipped",
Expand All @@ -27,19 +27,19 @@
"integration-test:browser": "echo skipped",
"integration-test:node": "echo skipped",
"integration-test": "npm run integration-test:node && npm run integration-test:browser",
"lint:fix": "eslint package.json api-extractor.json src test --ext .ts --fix --fix-type [problem,suggestion]",
"lint": "eslint package.json api-extractor.json src test --ext .ts",
"lint:fix": "eslint package.json api-extractor.json src --ext .ts --fix --fix-type [problem,suggestion]",
"lint": "eslint package.json api-extractor.json src --ext .ts",
"pack": "npm pack 2>&1",
"test:browser": "npm run clean && npm run build:test && npm run unit-test:browser && npm run integration-test:browser",
"test:node": "npm run clean && tsc -p . && npm run unit-test:node && npm run integration-test:node",
"test": "npm run clean && tsc -p . && npm run unit-test:node && dev-tool run bundle && npm run unit-test:browser && npm run integration-test",
"unit-test:browser": "karma start --single-run",
"unit-test:node": "dev-tool run test:node-ts-input --no-test-proxy=true",
"test:browser": "npm run build:test && npm run unit-test:browser && npm run integration-test:browser",
"test:node": "npm run unit-test:node && npm run integration-test:node",
"test": "npm run test:node && npm run test:browser",
"unit-test:browser": "vitest -c vitest.browser.config.mts",
"unit-test:node": "vitest",
"unit-test": "npm run unit-test:node && npm run unit-test:browser"
},
"files": [
"dist/",
"dist-esm/src/",
"dist-esm/",
"types/latest/core-util.d.ts",
"README.md",
"LICENSE"
Expand All @@ -66,34 +66,20 @@
},
"devDependencies": {
"@azure/dev-tool": "^1.0.0",
"@azure/eslint-plugin-azure-sdk": "^3.0.0",
"@azure-tools/vite-plugin-browser-test-map": "^1.0.0",
"@microsoft/api-extractor": "^7.31.1",
"@types/chai": "^4.1.6",
"@types/chai-as-promised": "^7.1.4",
"@types/mocha": "^10.0.0",
"@types/node": "^18.0.0",
"@types/sinon": "^17.0.0",
"@azure/eslint-plugin-azure-sdk": "^3.0.0",
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"@vitest/browser": "^1.1.0",
"downlevel-dts": "^0.10.0",
"cross-env": "^7.0.2",
"eslint": "^8.0.0",
"inherits": "^2.0.3",
"karma": "^6.2.0",
"karma-chrome-launcher": "^3.0.0",
"karma-coverage": "^2.0.0",
"karma-env-preprocessor": "^0.1.1",
"karma-firefox-launcher": "^1.1.0",
"karma-junit-reporter": "^2.0.1",
"karma-mocha": "^2.0.1",
"karma-mocha-reporter": "^2.2.5",
"karma-sourcemap-loader": "^0.3.8",
"mocha": "^10.0.0",
"prettier": "^2.5.1",
"playwright": "^1.39.0",
"rimraf": "^3.0.0",
"sinon": "^17.0.0",
"typescript": "~5.2.0",
"util": "^0.12.1",
"ts-node": "^10.0.0"
"vitest": "^1.1.0"
},
"//metadata": {
"migrationDate": "2023-03-08T18:36:03.000Z"
Expand Down
2 changes: 1 addition & 1 deletion sdk/core/core-util/review/core-util.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
```ts

import { AbortSignalLike } from '@azure/abort-controller';
import type { AbortSignalLike } from '@azure/abort-controller';

// @public
export type AbortablePromiseBuilder<T> = (abortOptions: {
Expand Down
2 changes: 1 addition & 1 deletion sdk/core/core-util/src/aborterUtils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import { AbortSignalLike } from "@azure/abort-controller";
import type { AbortSignalLike } from "@azure/abort-controller";

/**
* Options related to abort controller.
Expand Down
2 changes: 1 addition & 1 deletion sdk/core/core-util/src/createAbortablePromise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the MIT license.

import { AbortError } from "@azure/abort-controller";
import { AbortOptions } from "./aborterUtils";
import type { AbortOptions } from "./aborterUtils";

/**
* Options for the createAbortablePromise function.
Expand Down
2 changes: 1 addition & 1 deletion sdk/core/core-util/src/delay.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import { AbortOptions } from "./aborterUtils";
import type { AbortOptions } from "./aborterUtils";
import { createAbortablePromise } from "./createAbortablePromise";

const StandardAbortMessage = "The delay was aborted.";
Expand Down
17 changes: 12 additions & 5 deletions sdk/core/core-util/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

export { delay, DelayOptions } from "./delay";
export { AbortOptions, cancelablePromiseRace, AbortablePromiseBuilder } from "./aborterUtils";
export { createAbortablePromise, CreateAbortablePromiseOptions } from "./createAbortablePromise";
export { delay, type DelayOptions } from "./delay";
export {
type AbortOptions,
cancelablePromiseRace,
type AbortablePromiseBuilder,
} from "./aborterUtils";
export {
createAbortablePromise,
type CreateAbortablePromiseOptions,
} from "./createAbortablePromise";
export { getRandomIntegerInclusive } from "./random";
export { isObject, UnknownObject } from "./object";
export { isObject, type UnknownObject } from "./object";
export { isError, getErrorMessage } from "./error";
export { computeSha256Hash, computeSha256Hmac } from "./sha256";
export { isDefined, isObjectWithProperties, objectHasProperty } from "./typeGuards";
export { randomUUID } from "./uuidUtils";
export { isBrowser, isBun, isNode, isDeno, isReactNative, isWebWorker } from "./checkEnvironment";
export { uint8ArrayToString, stringToUint8Array, EncodingType } from "./bytesEncoding";
export { uint8ArrayToString, stringToUint8Array, type EncodingType } from "./bytesEncoding";
23 changes: 9 additions & 14 deletions sdk/core/core-util/test/public/aborterUtils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import * as sinon from "sinon";
import { AbortSignalLike } from "@azure/abort-controller";
import chai from "chai";
import chaiAsPromised from "chai-as-promised";
import type { AbortSignalLike } from "@azure/abort-controller";
import { describe, it, assert, expect, afterEach, vi } from "vitest";
import { cancelablePromiseRace, createAbortablePromise } from "../../src";

chai.use(chaiAsPromised);
const { assert } = chai;

describe("createAbortablePromise", function () {
let token: ReturnType<typeof setTimeout>;
const delayTime = 2500;
Expand All @@ -28,16 +23,16 @@ describe("createAbortablePromise", function () {
}
);
afterEach(function () {
sinon.restore();
vi.useRealTimers();
});

it("should resolve if not aborted nor rejected", async function () {
const clock = sinon.useFakeTimers();
const clock = vi.useFakeTimers();
const promise = createPromise();
const time = await clock.nextAsync();
clock.restore();
assert.strictEqual(time, delayTime);
await assert.isFulfilled(promise);
await clock.advanceTimersToNextTimerAsync();
assert.strictEqual(clock.getTimerCount(), 0);
clock.useRealTimers();
await expect(promise).resolves.toBeUndefined();
});

it("should reject when aborted", async function () {
Expand All @@ -48,7 +43,7 @@ describe("createAbortablePromise", function () {
abortErrorMsg,
});
aborter.abort();
await assert.isRejected(promise, abortErrorMsg);
await expect(promise).rejects.toThrowError(abortErrorMsg);
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the MIT license.

import { isBrowser, isBun, isDeno, isNode, isReactNative, isWebWorker } from "../../../src";
import { assert } from "chai";
import { describe, it, assert } from "vitest";

describe("checkEnvironment (browser)", function () {
describe("isBun (browser)", function () {
Expand Down
2 changes: 1 addition & 1 deletion sdk/core/core-util/test/public/bytesEncoding.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import { describe, it, assert } from "vitest";
import { stringToUint8Array, uint8ArrayToString } from "../../src/bytesEncoding";
import { assert } from "chai";

describe("bytesEncoding", function () {
describe("base64ToBytes", function () {
Expand Down
Loading

0 comments on commit ed4eda1

Please sign in to comment.