diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 000000000..9f4ae1a2c --- /dev/null +++ b/jest.config.js @@ -0,0 +1,27 @@ +const { pathsToModuleNameMapper } = require("ts-jest"); + +const { compilerOptions } = require("./tsconfig"); + +/** @type {import('jest').Config} */ +module.exports = { + reporters: ["default", "jest-junit"], + + collectCoverage: true, + coverageReporters: ["html", "lcov"], + coverageDirectory: "coverage", + + moduleNameMapper: pathsToModuleNameMapper(compilerOptions?.paths || {}, { + prefix: "/", + }), + projects: [ + "/jslib/angular/jest.config.js", + "/jslib/common/jest.config.js", + "/jslib/electron/jest.config.js", + "/jslib/node/jest.config.js", + ], + + // Workaround for a memory leak that crashes tests in CI: + // https://github.com/facebook/jest/issues/9430#issuecomment-1149882002 + // Also anecdotally improves performance when run locally + maxWorkers: 3, +}; diff --git a/jslib/angular/jest.config.js b/jslib/angular/jest.config.js index 19d250fc9..25a1d4f87 100644 --- a/jslib/angular/jest.config.js +++ b/jslib/angular/jest.config.js @@ -1,16 +1,15 @@ -const { pathsToModuleNameMapper } = require("ts-jest/utils"); +const { pathsToModuleNameMapper } = require("ts-jest"); -const { compilerOptions } = require("./tsconfig"); +const { compilerOptions } = require("../shared/tsconfig.libs"); +const sharedConfig = require("../shared/jest.config.angular"); + +/** @type {import('jest').Config} */ module.exports = { - name: "angular", - displayName: "angular tests", + ...sharedConfig, + displayName: "libs/angular tests", preset: "jest-preset-angular", - testMatch: ["**/+(*.)+(spec).+(ts)"], - setupFilesAfterEnv: ["/spec/test.ts"], - collectCoverage: true, - coverageReporters: ["html", "lcov"], - coverageDirectory: "coverage", + setupFilesAfterEnv: ["/test.setup.ts"], moduleNameMapper: pathsToModuleNameMapper(compilerOptions?.paths || {}, { prefix: "/", }), diff --git a/jslib/angular/test.setup.ts b/jslib/angular/test.setup.ts new file mode 100644 index 000000000..6be6e7b8d --- /dev/null +++ b/jslib/angular/test.setup.ts @@ -0,0 +1,28 @@ +import { webcrypto } from "crypto"; +import "jest-preset-angular/setup-jest"; + +Object.defineProperty(window, "CSS", { value: null }); +Object.defineProperty(window, "getComputedStyle", { + value: () => { + return { + display: "none", + appearance: ["-webkit-appearance"], + }; + }, +}); + +Object.defineProperty(document, "doctype", { + value: "", +}); +Object.defineProperty(document.body.style, "transform", { + value: () => { + return { + enumerable: true, + configurable: true, + }; + }, +}); + +Object.defineProperty(window, "crypto", { + value: webcrypto, +}); diff --git a/jslib/common/jest.config.js b/jslib/common/jest.config.js index 76856611f..d7f78abbf 100644 --- a/jslib/common/jest.config.js +++ b/jslib/common/jest.config.js @@ -1,17 +1,16 @@ -const { pathsToModuleNameMapper } = require("ts-jest/utils"); +const { pathsToModuleNameMapper } = require("ts-jest"); -const { compilerOptions } = require("./tsconfig"); +const { compilerOptions } = require("../shared/tsconfig.libs"); +const sharedConfig = require("../shared/jest.config.ts"); + +/** @type {import('jest').Config} */ module.exports = { - name: "common", - displayName: "common jslib tests", + ...sharedConfig, + displayName: "libs/common tests", preset: "ts-jest", testEnvironment: "jsdom", - testMatch: ["**/+(*.)+(spec).+(ts)"], - setupFilesAfterEnv: ["/spec/test.ts"], - collectCoverage: true, - coverageReporters: ["html", "lcov"], - coverageDirectory: "coverage", + setupFilesAfterEnv: ["/test.setup.ts"], moduleNameMapper: pathsToModuleNameMapper(compilerOptions?.paths || {}, { prefix: "/", }), diff --git a/jslib/common/spec/index.ts b/jslib/common/spec/index.ts new file mode 100644 index 000000000..514a64030 --- /dev/null +++ b/jslib/common/spec/index.ts @@ -0,0 +1 @@ +export * from "./matchers"; diff --git a/jslib/common/spec/matchers/index.ts b/jslib/common/spec/matchers/index.ts new file mode 100644 index 000000000..59f6409fe --- /dev/null +++ b/jslib/common/spec/matchers/index.ts @@ -0,0 +1 @@ +export * from "./to-equal-buffer"; diff --git a/jslib/common/spec/matchers/to-equal-buffer.spec.ts b/jslib/common/spec/matchers/to-equal-buffer.spec.ts new file mode 100644 index 000000000..ccf574236 --- /dev/null +++ b/jslib/common/spec/matchers/to-equal-buffer.spec.ts @@ -0,0 +1,25 @@ +import { makeStaticByteArray } from "../utils"; + +describe("toEqualBuffer custom matcher", () => { + it("matches identical ArrayBuffers", () => { + const array = makeStaticByteArray(10); + expect(array.buffer).toEqualBuffer(array.buffer); + }); + + it("matches an identical ArrayBuffer and Uint8Array", () => { + const array = makeStaticByteArray(10); + expect(array.buffer).toEqualBuffer(array); + }); + + it("doesn't match different ArrayBuffers", () => { + const array1 = makeStaticByteArray(10); + const array2 = makeStaticByteArray(10, 11); + expect(array1.buffer).not.toEqualBuffer(array2.buffer); + }); + + it("doesn't match a different ArrayBuffer and Uint8Array", () => { + const array1 = makeStaticByteArray(10); + const array2 = makeStaticByteArray(10, 11); + expect(array1.buffer).not.toEqualBuffer(array2); + }); +}); diff --git a/jslib/common/spec/matchers/to-equal-buffer.ts b/jslib/common/spec/matchers/to-equal-buffer.ts new file mode 100644 index 000000000..5639f10a9 --- /dev/null +++ b/jslib/common/spec/matchers/to-equal-buffer.ts @@ -0,0 +1,31 @@ +/** + * The inbuilt toEqual() matcher will always return TRUE when provided with 2 ArrayBuffers. + * This is because an ArrayBuffer must be wrapped in a new Uint8Array to be accessible. + * This custom matcher will automatically instantiate a new Uint8Array on the received value + * (and optionally, the expected value) and then call toEqual() on the resulting Uint8Arrays. + */ +export const toEqualBuffer: jest.CustomMatcher = function ( + received: ArrayBuffer | Uint8Array, + expected: ArrayBuffer | Uint8Array, +) { + received = new Uint8Array(received); + expected = new Uint8Array(expected); + + if (this.equals(received, expected)) { + return { + message: () => `expected +${received} +not to match +${expected}`, + pass: true, + }; + } + + return { + message: () => `expected +${received} +to match +${expected}`, + pass: false, + }; +}; diff --git a/jslib/common/spec/utils.ts b/jslib/common/spec/utils.ts index 58963d0f8..1860e9e75 100644 --- a/jslib/common/spec/utils.ts +++ b/jslib/common/spec/utils.ts @@ -28,10 +28,10 @@ export function mockEnc(s: string): EncString { return mock; } -export function makeStaticByteArray(length: number) { +export function makeStaticByteArray(length: number, start = 0) { const arr = new Uint8Array(length); for (let i = 0; i < length; i++) { - arr[i] = i; + arr[i] = start + i; } return arr; } diff --git a/jslib/common/test.setup.ts b/jslib/common/test.setup.ts new file mode 100644 index 000000000..c50c7ca22 --- /dev/null +++ b/jslib/common/test.setup.ts @@ -0,0 +1,17 @@ +import { webcrypto } from "crypto"; + +import { toEqualBuffer } from "./spec"; + +Object.defineProperty(window, "crypto", { + value: webcrypto, +}); + +// Add custom matchers + +expect.extend({ + toEqualBuffer: toEqualBuffer, +}); + +export interface CustomMatchers { + toEqualBuffer(expected: Uint8Array | ArrayBuffer): R; +} diff --git a/jslib/electron/jest.config.js b/jslib/electron/jest.config.js index 8d59aeafe..ee692181f 100644 --- a/jslib/electron/jest.config.js +++ b/jslib/electron/jest.config.js @@ -1,15 +1,16 @@ -const { pathsToModuleNameMapper } = require("ts-jest/utils"); +const { pathsToModuleNameMapper } = require("ts-jest"); -const { compilerOptions } = require("./tsconfig"); +const { compilerOptions } = require("../shared/tsconfig.libs"); +const sharedConfig = require("../shared/jest.config.ts"); + +/** @type {import('jest').Config} */ module.exports = { + ...sharedConfig, + displayName: "libs/electron tests", preset: "ts-jest", - testEnvironment: "jsdom", - testMatch: ["**/+(*.)+(spec).+(ts)"], - setupFilesAfterEnv: ["/spec/test.ts"], - collectCoverage: true, - coverageReporters: ["html", "lcov"], - coverageDirectory: "coverage", + testEnvironment: "node", + setupFilesAfterEnv: ["/test.setup.ts"], moduleNameMapper: pathsToModuleNameMapper(compilerOptions?.paths || {}, { prefix: "/", }), diff --git a/jslib/electron/test.setup.ts b/jslib/electron/test.setup.ts new file mode 100644 index 000000000..e69de29bb diff --git a/jslib/jest.config.js b/jslib/jest.config.js deleted file mode 100644 index fabe9db7f..000000000 --- a/jslib/jest.config.js +++ /dev/null @@ -1,18 +0,0 @@ -const { pathsToModuleNameMapper } = require("ts-jest/utils"); - -const { compilerOptions } = require("./tsconfig"); - -module.exports = { - collectCoverage: true, - coverageReporters: ["html", "lcov"], - coverageDirectory: "coverage", - moduleNameMapper: pathsToModuleNameMapper(compilerOptions?.paths || {}, { - prefix: "/", - }), - projects: [ - "/angular/jest.config.js", - "/common/jest.config.js", - "/electron/jest.config.js", - "/node/jest.config.js", - ], -}; diff --git a/jslib/node/jest.config.js b/jslib/node/jest.config.js index f1bfb7a9b..d8dce6040 100644 --- a/jslib/node/jest.config.js +++ b/jslib/node/jest.config.js @@ -1,14 +1,16 @@ -const { pathsToModuleNameMapper } = require("ts-jest/utils"); +const { pathsToModuleNameMapper } = require("ts-jest"); -const { compilerOptions } = require("./tsconfig"); +const { compilerOptions } = require("../shared/tsconfig.libs"); +const sharedConfig = require("../shared/jest.config.ts"); + +/** @type {import('jest').Config} */ module.exports = { + ...sharedConfig, + displayName: "libs/node tests", preset: "ts-jest", - testMatch: ["**/+(*.)+(spec).+(ts)"], - setupFilesAfterEnv: ["/spec/test.ts"], - collectCoverage: true, - coverageReporters: ["html", "lcov"], - coverageDirectory: "coverage", + testEnvironment: "node", + setupFilesAfterEnv: ["/test.setup.ts"], moduleNameMapper: pathsToModuleNameMapper(compilerOptions?.paths || {}, { prefix: "/", }), diff --git a/jslib/node/test.setup.ts b/jslib/node/test.setup.ts new file mode 100644 index 000000000..e69de29bb diff --git a/jslib/package-lock.json b/jslib/package-lock.json deleted file mode 100644 index ebb4ca6ae..000000000 --- a/jslib/package-lock.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "@bitwarden/jslib", - "version": "0.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "@bitwarden/jslib", - "version": "0.0.0", - "license": "GPL-3.0" - } - } -} diff --git a/jslib/package.json b/jslib/package.json deleted file mode 100644 index ce02eb908..000000000 --- a/jslib/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "@bitwarden/jslib", - "version": "0.0.0", - "description": "Common code used across Bitwarden JavaScript projects.", - "keywords": [ - "bitwarden" - ], - "author": "Bitwarden Inc.", - "homepage": "https://bitwarden.com", - "repository": { - "type": "git", - "url": "https://github.com/bitwarden/jslib" - }, - "license": "GPL-3.0", - "scripts": { - "clean": "rimraf dist/**/*", - "test": "jest", - "test:watch": "jest --watch", - "test:watch:all": "jest --watchAll" - }, - "dependencies": {} -} diff --git a/jslib/shared/es2020-transformer.ts b/jslib/shared/es2020-transformer.ts new file mode 100644 index 000000000..3a26e1c0c --- /dev/null +++ b/jslib/shared/es2020-transformer.ts @@ -0,0 +1,36 @@ +import * as ts from "typescript"; + +// Custom Typescript AST transformer for use with ts-jest / jest-preset-angular +// Removes specified ES2020 syntax from source code, as node does not support it yet +// Reference: https://kulshekhar.github.io/ts-jest/docs/getting-started/options/astTransformers +// Use this tool to understand how we identify and filter AST nodes: https://ts-ast-viewer.com/ + +/** + * Remember to increase the version whenever transformer's content is changed. This is to inform Jest to not reuse + * the previous cache which contains old transformer's content + */ +export const version = 1; +export const name = "bit-es2020-transformer"; + +// Returns true for 'import.meta' statements +const isImportMetaStatement = (node: ts.Node) => + ts.isPropertyAccessExpression(node) && + ts.isMetaProperty(node.expression) && + node.expression.keywordToken === ts.SyntaxKind.ImportKeyword; + +export const factory = function (/*opts?: Opts*/) { + function visitor(ctx: ts.TransformationContext, sf: ts.SourceFile) { + const visitor: ts.Visitor = (node: ts.Node): ts.VisitResult => { + if (isImportMetaStatement(node)) { + return null; + } + + // Continue searching child nodes + return ts.visitEachChild(node, visitor, ctx); + }; + return visitor; + } + return (ctx: ts.TransformationContext): ts.Transformer => { + return (sf: ts.SourceFile) => ts.visitNode(sf, visitor(ctx, sf)); + }; +}; diff --git a/jslib/shared/jest.config.angular.js b/jslib/shared/jest.config.angular.js new file mode 100644 index 000000000..ca86d9089 --- /dev/null +++ b/jslib/shared/jest.config.angular.js @@ -0,0 +1,32 @@ +/* eslint-env node */ +/* eslint-disable @typescript-eslint/no-var-requires */ +const { defaultTransformerOptions } = require("jest-preset-angular/presets"); + +/** @type {import('jest').Config} */ +module.exports = { + testMatch: ["**/+(*.)+(spec).+(ts)"], + + // Workaround for a memory leak that crashes tests in CI: + // https://github.com/facebook/jest/issues/9430#issuecomment-1149882002 + // Also anecdotally improves performance when run locally + maxWorkers: 3, + + transform: { + "^.+\\.(ts|js|mjs|svg)$": [ + "jest-preset-angular", + { + ...defaultTransformerOptions, + // Jest does not use tsconfig.spec.json by default + tsconfig: "/tsconfig.spec.json", + // Further workaround for memory leak, recommended here: + // https://github.com/kulshekhar/ts-jest/issues/1967#issuecomment-697494014 + // Makes tests run faster and reduces size/rate of leak, but loses typechecking on test code + // See https://bitwarden.atlassian.net/browse/EC-497 for more info + isolatedModules: true, + astTransformers: { + before: ["/../../jslib/shared/es2020-transformer.ts"], + }, + }, + ], + }, +}; diff --git a/jslib/shared/jest.config.ts.js b/jslib/shared/jest.config.ts.js new file mode 100644 index 000000000..970e421ab --- /dev/null +++ b/jslib/shared/jest.config.ts.js @@ -0,0 +1,29 @@ +/* eslint-env node */ + +/** @type {import('jest').Config} */ +module.exports = { + testMatch: ["**/+(*.)+(spec).+(ts)"], + + // Workaround for a memory leak that crashes tests in CI: + // https://github.com/facebook/jest/issues/9430#issuecomment-1149882002 + // Also anecdotally improves performance when run locally + maxWorkers: 3, + + transform: { + "^.+\\.tsx?$": [ + "ts-jest", + { + // Jest does not use tsconfig.spec.json by default + tsconfig: "/tsconfig.spec.json", + // Further workaround for memory leak, recommended here: + // https://github.com/kulshekhar/ts-jest/issues/1967#issuecomment-697494014 + // Makes tests run faster and reduces size/rate of leak, but loses typechecking on test code + // See https://bitwarden.atlassian.net/browse/EC-497 for more info + isolatedModules: true, + astTransformers: { + before: ["/../../jslib/shared/es2020-transformer.ts"], + }, + }, + ], + }, +}; diff --git a/jslib/shared/test.environment.ts b/jslib/shared/test.environment.ts new file mode 100644 index 000000000..404303d1a --- /dev/null +++ b/jslib/shared/test.environment.ts @@ -0,0 +1,22 @@ +import JSDOMEnvironment from "jest-environment-jsdom"; + +/** + * https://github.com/jsdom/jsdom/issues/3363#issuecomment-1467894943 + * Adds nodes structuredClone implementation to the global object of jsdom. + * use by either adding this file to the testEnvironment property of jest config + * or by adding the following to the top spec file: + * + * ``` + * /** + * * @jest-environment ../shared/test.environment.ts + * *\/ + * ``` + */ +export default class FixJSDOMEnvironment extends JSDOMEnvironment { + constructor(...args: ConstructorParameters) { + super(...args); + + // FIXME https://github.com/jsdom/jsdom/issues/3363 + this.global.structuredClone = structuredClone; + } +} diff --git a/jslib/shared/tsconfig.libs.json b/jslib/shared/tsconfig.libs.json new file mode 100644 index 000000000..6989026aa --- /dev/null +++ b/jslib/shared/tsconfig.libs.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig", + "compilerOptions": { + "paths": { + "tldjs": ["../common/src/misc/tldjs.noop"], + "jslib-common/*": ["../common/src/*"], + "jslib-angular/*": ["../angular/src/*"], + "jslib-electron/*": ["../electron/src/*"], + "jslib-node/*": ["../node/src/*"] + } + } +} diff --git a/package-lock.json b/package-lock.json index 64acc9a7b..5b96d68fa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -96,6 +96,7 @@ "html-webpack-plugin": "5.5.3", "husky": "8.0.3", "jest": "29.6.4", + "jest-junit": "^16.0.0", "jest-preset-angular": "13.1.1", "jsdom": "22.1.0", "lint-staged": "12.5.0", @@ -111,6 +112,7 @@ "sass": "1.66.1", "sass-loader": "12.6.0", "tapable": "1.1.3", + "ts-jest": "^29.1.1", "ts-loader": "9.4.4", "ts-node": "10.9.1", "tsconfig-paths": "3.14.2", @@ -13448,6 +13450,33 @@ "fsevents": "^2.3.2" } }, + "node_modules/jest-junit": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-16.0.0.tgz", + "integrity": "sha512-A94mmw6NfJab4Fg/BlvVOUXzXgF0XIH6EmTgJ5NDPp4xoKq0Kr7sErb+4Xs9nZvu58pJojz5RFGpqnZYJTrRfQ==", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "strip-ansi": "^6.0.1", + "uuid": "^8.3.2", + "xml": "^1.0.1" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/jest-junit/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/jest-leak-detector": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.6.3.tgz", @@ -20089,9 +20118,9 @@ } }, "node_modules/ts-jest": { - "version": "29.1.0", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.0.tgz", - "integrity": "sha512-ZhNr7Z4PcYa+JjMl62ir+zPiNJfXJN6E8hSLnaUKhOgqcn8vb3e537cpkd0FuAfRK3sR1LSqM1MOhliXNgOFPA==", + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz", + "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==", "dev": true, "dependencies": { "bs-logger": "0.x", @@ -20100,7 +20129,7 @@ "json5": "^2.2.3", "lodash.memoize": "4.x", "make-error": "1.x", - "semver": "7.x", + "semver": "^7.5.3", "yargs-parser": "^21.0.1" }, "bin": { @@ -21474,6 +21503,12 @@ } } }, + "node_modules/xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", + "dev": true + }, "node_modules/xml-name-validator": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", @@ -31483,6 +31518,26 @@ "walker": "^1.0.8" } }, + "jest-junit": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-16.0.0.tgz", + "integrity": "sha512-A94mmw6NfJab4Fg/BlvVOUXzXgF0XIH6EmTgJ5NDPp4xoKq0Kr7sErb+4Xs9nZvu58pJojz5RFGpqnZYJTrRfQ==", + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "strip-ansi": "^6.0.1", + "uuid": "^8.3.2", + "xml": "^1.0.1" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + } + } + }, "jest-leak-detector": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.6.3.tgz", @@ -36519,9 +36574,9 @@ } }, "ts-jest": { - "version": "29.1.0", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.0.tgz", - "integrity": "sha512-ZhNr7Z4PcYa+JjMl62ir+zPiNJfXJN6E8hSLnaUKhOgqcn8vb3e537cpkd0FuAfRK3sR1LSqM1MOhliXNgOFPA==", + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz", + "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==", "dev": true, "requires": { "bs-logger": "0.x", @@ -36530,7 +36585,7 @@ "json5": "^2.2.3", "lodash.memoize": "4.x", "make-error": "1.x", - "semver": "7.x", + "semver": "^7.5.3", "yargs-parser": "^21.0.1" } }, @@ -37486,6 +37541,12 @@ "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "requires": {} }, + "xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", + "dev": true + }, "xml-name-validator": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", diff --git a/package.json b/package.json index 29c07704f..3aacc49f3 100644 --- a/package.json +++ b/package.json @@ -62,9 +62,9 @@ "publish:win": "npm run build:dist && npm run clean:dist && electron-builder --win --x64 --ia32 -p always -c.win.certificateSubjectName=\"8bit Solutions LLC\"", "prettier": "prettier --write .", "prepare": "husky install", - "test:jslib": "jest", - "test:jslib:watch": "jest --watch", - "test:jslib:watch:all": "jest --watchAll" + "test": "jest", + "test:watch": "jest --watch", + "test:watch:all": "jest --watchAll" }, "devDependencies": { "@angular-devkit/build-angular": "15.2.9", @@ -78,9 +78,9 @@ "@types/ldapjs": "2.2.5", "@types/lowdb": "1.0.11", "@types/lunr": "2.3.4", + "@types/node": "18.17.12", "@types/node-fetch": "2.6.4", "@types/node-forge": "1.3.4", - "@types/node": "18.17.12", "@types/papaparse": "5.3.8", "@types/proper-lockfile": "4.1.2", "@types/tldjs": "2.3.1", @@ -93,6 +93,7 @@ "copy-webpack-plugin": "11.0.0", "cross-env": "7.0.3", "css-loader": "6.8.1", + "electron": "18.3.15", "electron-builder": "24.6.3", "electron-log": "4.4.8", "electron-notarize": "1.2.2", @@ -100,17 +101,17 @@ "electron-reload": "1.5.0", "electron-store": "8.1.0", "electron-updater": "5.3.0", - "electron": "18.3.15", + "eslint": "8.48.0", "eslint-config-prettier": "8.10.0", "eslint-import-resolver-typescript": "2.7.1", "eslint-plugin-import": "2.28.1", - "eslint": "8.48.0", "form-data": "4.0.0", "html-loader": "3.1.2", "html-webpack-plugin": "5.5.3", "husky": "8.0.3", - "jest-preset-angular": "13.1.1", "jest": "29.6.4", + "jest-junit": "^16.0.0", + "jest-preset-angular": "13.1.1", "jsdom": "22.1.0", "lint-staged": "12.5.0", "mini-css-extract-plugin": "2.7.6", @@ -122,21 +123,22 @@ "prettier": "2.8.8", "rimraf": "3.0.2", "rxjs": "7.8.1", - "sass-loader": "12.6.0", "sass": "1.66.1", + "sass-loader": "12.6.0", "tapable": "1.1.3", + "ts-jest": "^29.1.1", "ts-loader": "9.4.4", "ts-node": "10.9.1", - "tsconfig-paths-webpack-plugin": "4.1.0", "tsconfig-paths": "3.14.2", + "tsconfig-paths-webpack-plugin": "4.1.0", "ttypescript": "1.5.15", "typemoq": "2.1.0", - "typescript-transform-paths": "2.2.4", "typescript": "4.9.5", + "typescript-transform-paths": "2.2.4", + "webpack": "5.88.2", "webpack-cli": "5.1.4", "webpack-merge": "5.9.0", "webpack-node-externals": "3.0.0", - "webpack": "5.88.2", "zone.js": "0.13.1" }, "dependencies": {