Feature/move to jest (#744)

* Switch to jest

* Fix jslib-angular package name

* Make angular test project

* Split up tests by jslib project

* Remove obsolete node test script

* Use legacy deps with jest-preset-angular

* Move web tests to common

* Remove build from pipeline

This was only being used because we were not using ts runners.
We are now, so build is unnecessary
This commit is contained in:
Matt Gibson 2022-03-28 10:00:42 -04:00 committed by GitHub
parent 13ef7aea7d
commit a4fba0e1c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
112 changed files with 5526 additions and 2221 deletions

View File

@ -1,3 +1,4 @@
**/dist
**/jest.config.js
**/node_modules

View File

@ -53,9 +53,6 @@ jobs:
- name: Run linter
run: npm run lint
- name: Build
run: npm run build
- name: Run tests
if: runner.os != 'Linux'
run: npm run test
@ -67,9 +64,6 @@ jobs:
name: test-coverage
path: coverage/
- name: Run Node tests
run: npm run test:node
check-failures:
name: Check for failures
if: always()

18
angular/jest.config.js Normal file
View File

@ -0,0 +1,18 @@
const { pathsToModuleNameMapper } = require("ts-jest/utils");
const { compilerOptions } = require("./tsconfig");
module.exports = {
name: "angular",
displayName: "angular tests",
preset: "jest-preset-angular",
roots: ["<rootDir>/spec/"],
testMatch: ["**/+(*.)+(spec).+(ts)"],
setupFilesAfterEnv: ["<rootDir>/spec/test.ts"],
collectCoverage: true,
coverageReporters: ["html", "lcov"],
coverageDirectory: "coverage",
moduleNameMapper: pathsToModuleNameMapper(compilerOptions?.paths || {}, {
prefix: "<rootDir>/",
}),
};

View File

@ -1,11 +1,11 @@
{
"name": "@bitwarden/jslib-common",
"name": "@bitwarden/jslib-angular",
"version": "0.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@bitwarden/jslib-common",
"name": "@bitwarden/jslib-angular",
"version": "0.0.0",
"license": "GPL-3.0",
"dependencies": {
@ -31,6 +31,7 @@
}
},
"../common": {
"name": "@bitwarden/jslib-common",
"version": "0.0.0",
"license": "GPL-3.0",
"dependencies": {
@ -39,7 +40,7 @@
"big-integer": "1.6.48",
"browser-hrtime": "^1.1.8",
"lunr": "^2.3.9",
"node-forge": "^0.10.0",
"node-forge": "^1.2.1",
"papaparse": "^5.3.0",
"rxjs": "^7.4.0",
"tldjs": "^2.3.1",
@ -47,8 +48,8 @@
},
"devDependencies": {
"@types/lunr": "^2.3.3",
"@types/node": "^14.17.1",
"@types/node-forge": "^0.9.7",
"@types/node": "^16.11.12",
"@types/node-forge": "^1.0.1",
"@types/papaparse": "^5.2.5",
"@types/tldjs": "^2.3.0",
"@types/zxcvbn": "^4.4.1",
@ -472,15 +473,15 @@
"@microsoft/signalr": "5.0.10",
"@microsoft/signalr-protocol-msgpack": "5.0.10",
"@types/lunr": "^2.3.3",
"@types/node": "^14.17.1",
"@types/node-forge": "^0.9.7",
"@types/node": "^16.11.12",
"@types/node-forge": "^1.0.1",
"@types/papaparse": "^5.2.5",
"@types/tldjs": "^2.3.0",
"@types/zxcvbn": "^4.4.1",
"big-integer": "1.6.48",
"browser-hrtime": "^1.1.8",
"lunr": "^2.3.9",
"node-forge": "^0.10.0",
"node-forge": "^1.2.1",
"papaparse": "^5.3.0",
"rimraf": "^3.0.2",
"rxjs": "^7.4.0",

View File

@ -1,5 +1,5 @@
{
"name": "@bitwarden/jslib-common",
"name": "@bitwarden/jslib-angular",
"version": "0.0.0",
"description": "Common code used across Bitwarden JavaScript projects.",
"keywords": [

28
angular/spec/test.ts Normal file
View File

@ -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: "<!DOCTYPE html>",
});
Object.defineProperty(document.body.style, "transform", {
value: () => {
return {
enumerable: true,
configurable: true,
};
},
});
Object.defineProperty(window, "crypto", {
value: webcrypto,
});

View File

@ -2,7 +2,8 @@
"extends": "../shared/tsconfig",
"compilerOptions": {
"paths": {
"jslib-common/*": ["../common/src/*"]
"jslib-common/*": ["../common/src/*"],
"jslib-angular/*": ["./src/"]
}
},
"include": ["src", "spec"],

View File

@ -0,0 +1,3 @@
{
"extends": "./tsconfig.json"
}

19
common/jest.config.js Normal file
View File

@ -0,0 +1,19 @@
const { pathsToModuleNameMapper } = require("ts-jest/utils");
const { compilerOptions } = require("./tsconfig");
module.exports = {
name: "common",
displayName: "common jslib tests",
preset: "ts-jest",
testEnvironment: "jsdom",
roots: ["<rootDir>/spec/"],
testMatch: ["**/+(*.)+(spec).+(ts)"],
setupFilesAfterEnv: ["<rootDir>/spec/test.ts"],
collectCoverage: true,
coverageReporters: ["html", "lcov"],
coverageDirectory: "coverage",
moduleNameMapper: pathsToModuleNameMapper(compilerOptions?.paths || {}, {
prefix: "<rootDir>/",
}),
};

View File

@ -30,14 +30,12 @@ import { WirelessRouterData } from "./testData/onePassword1Pux/WirelessRouter";
function validateCustomField(fields: FieldView[], fieldName: string, expectedValue: any) {
expect(fields).toBeDefined();
const customField = fields.find((f) => f.name === fieldName);
expect(customField).withContext(`CustomField: ('${fieldName}') was not found`).toBeDefined();
expect(customField).toBeDefined();
expect(customField.value)
.withContext(`Customfield: ('${fieldName}'), should be equal to: '${expectedValue}'`)
.toEqual(expectedValue);
expect(customField.value).toEqual(expectedValue);
}
describe("1Password 1Pux Importer", async () => {
describe("1Password 1Pux Importer", () => {
const OnePuxExampleFileJson = JSON.stringify(OnePuxExampleFile);
const LoginDataJson = JSON.stringify(LoginData);
const CreditCardDataJson = JSON.stringify(CreditCardData);
@ -83,7 +81,7 @@ describe("1Password 1Pux Importer", async () => {
expect(result != null).toBe(true);
const cipher = result.ciphers.shift();
expect(cipher.favorite).toBeTrue();
expect(cipher.favorite).toBe(true);
});
it("should handle custom boolean fields", async () => {

View File

@ -10,7 +10,7 @@ function expectIdentity(cipher: CipherView) {
expect(cipher.type).toBe(CipherType.Identity);
expect(cipher.identity).toEqual(
jasmine.objectContaining({
expect.objectContaining({
firstName: "first name",
middleName: "mi",
lastName: "last name",
@ -28,7 +28,7 @@ function expectCreditCard(cipher: CipherView) {
expect(cipher.type).toBe(CipherType.Card);
expect(cipher.card).toEqual(
jasmine.objectContaining({
expect.objectContaining({
number: "4111111111111111",
code: "111",
cardholderName: "test",

View File

@ -12,7 +12,7 @@ function expectIdentity(cipher: CipherView) {
expect(cipher.type).toBe(CipherType.Identity);
expect(cipher.identity).toEqual(
jasmine.objectContaining({
expect.objectContaining({
firstName: "first name",
middleName: "mi",
lastName: "last name",
@ -24,7 +24,7 @@ function expectIdentity(cipher: CipherView) {
);
expect(cipher.fields).toEqual(
jasmine.arrayContaining([
expect.arrayContaining([
Object.assign(new FieldView(), {
type: FieldType.Text,
name: "address",
@ -38,7 +38,7 @@ function expectCreditCard(cipher: CipherView) {
expect(cipher.type).toBe(CipherType.Card);
expect(cipher.card).toEqual(
jasmine.objectContaining({
expect.objectContaining({
number: "4111111111111111",
code: "111",
cardholderName: "test",

View File

@ -57,25 +57,25 @@ describe("ConsoleLogService", () => {
it("writes debug/info messages to console.log", () => {
logService.debug("this is a debug message");
expect(caughtMessage).toEqual({
log: jasmine.arrayWithExactContents(["this is a debug message"]),
expect(caughtMessage).toMatchObject({
log: { "0": "this is a debug message" },
});
logService.info("this is an info message");
expect(caughtMessage).toEqual({
log: jasmine.arrayWithExactContents(["this is an info message"]),
expect(caughtMessage).toMatchObject({
log: { "0": "this is an info message" },
});
});
it("writes warning messages to console.warn", () => {
logService.warning("this is a warning message");
expect(caughtMessage).toEqual({
warn: jasmine.arrayWithExactContents(["this is a warning message"]),
expect(caughtMessage).toMatchObject({
warn: { 0: "this is a warning message" },
});
});
it("writes error messages to console.error", () => {
logService.error("this is an error message");
expect(caughtMessage).toEqual({
error: jasmine.arrayWithExactContents(["this is an error message"]),
expect(caughtMessage).toMatchObject({
error: { 0: "this is an error message" },
});
});
@ -87,9 +87,9 @@ describe("ConsoleLogService", () => {
expect(duration[1]).toBeGreaterThan(0);
expect(duration[1]).toBeLessThan(500 * 10e6);
expect(caughtMessage).toEqual(jasmine.arrayContaining([]));
expect(caughtMessage).toEqual(expect.arrayContaining([]));
expect(caughtMessage.log.length).toBe(1);
expect(caughtMessage.log[0]).toEqual(jasmine.stringMatching(/^default: \d+\.?\d*ms$/));
expect(caughtMessage.log[0]).toEqual(expect.stringMatching(/^default: \d+\.?\d*ms$/));
});
it("filters time output", async () => {

View File

@ -16,7 +16,7 @@ import { CipherView } from "jslib-common/models/view/cipherView";
import { LoginView } from "jslib-common/models/view/loginView";
import { ExportService } from "jslib-common/services/export.service";
import { BuildTestObject, GetUniqueString } from "../../utils";
import { BuildTestObject, GetUniqueString } from "../utils";
const UserCipherViews = [
generateCipherView(false),
@ -154,10 +154,10 @@ describe("ExportService", () => {
mac = Substitute.for<EncString>();
data = Substitute.for<EncString>();
mac.encryptedString = "mac";
data.encryptedString = "encData";
mac.encryptedString.returns("mac");
data.encryptedString.returns("encData");
spyOn(Utils, "fromBufferToB64").and.returnValue(salt);
jest.spyOn(Utils, "fromBufferToB64").mockReturnValue(salt);
cipherService.getAllDecrypted().resolves(UserCipherViews.slice(0, 1));
exportString = await exportService.getPasswordProtectedExport(password);
@ -184,13 +184,19 @@ describe("ExportService", () => {
expect(exportObject.kdfType).toEqual(KdfType.PBKDF2_SHA256);
});
it("has a mac property", () => {
it("has a mac property", async () => {
cryptoService.encrypt(Arg.any(), Arg.any()).resolves(mac);
exportString = await exportService.getPasswordProtectedExport(password);
exportObject = JSON.parse(exportString);
expect(exportObject.encKeyValidation_DO_NOT_EDIT).toEqual(mac.encryptedString);
});
it("has data property", () => {
it("has data property", async () => {
cryptoService.encrypt(Arg.any(), Arg.any()).resolves(data);
exportString = await exportService.getPasswordProtectedExport(password);
exportObject = JSON.parse(exportString);
expect(exportObject.data).toEqual(data.encryptedString);
});

View File

@ -65,7 +65,7 @@ describe("ImportService", () => {
});
it("has the appropriate password", () => {
expect(Object.entries(importer)).toEqual(jasmine.arrayContaining([["password", password]]));
expect(Object.entries(importer)).toEqual(expect.arrayContaining([["password", password]]));
});
});
});

5
common/spec/test.ts Normal file
View File

@ -0,0 +1,5 @@
import { webcrypto } from "crypto";
Object.defineProperty(window, "crypto", {
value: webcrypto,
});

View File

@ -102,7 +102,7 @@ describe("WebCrypto Function Service", () => {
32,
"sha256"
);
await expectAsync(f).toBeRejectedWith(new Error("prk is too small."));
await expect(f).rejects.toEqual(new Error("prk is too small."));
});
it("should fail with outputByteSize is too large", async () => {
@ -113,7 +113,7 @@ describe("WebCrypto Function Service", () => {
8161,
"sha256"
);
await expectAsync(f).toBeRejectedWith(new Error("outputByteSize is too large."));
await expect(f).rejects.toEqual(new Error("outputByteSize is too large."));
});
});

View File

@ -1,5 +1,10 @@
{
"extends": "../shared/tsconfig",
"compilerOptions": {
"paths": {
"jslib-common/*": ["./src/*"]
}
},
"include": ["src", "spec"],
"exclude": ["node_modules", "dist"]
}

View File

@ -0,0 +1,3 @@
{
"extends": "./tsconfig.json"
}

17
electron/jest.config.js Normal file
View File

@ -0,0 +1,17 @@
const { pathsToModuleNameMapper } = require("ts-jest/utils");
const { compilerOptions } = require("./tsconfig");
module.exports = {
preset: "ts-jest",
testEnvironment: "jsdom",
roots: ["<rootDir>/spec/"],
testMatch: ["**/+(*.)+(spec).+(ts)"],
setupFilesAfterEnv: ["<rootDir>/spec/test.ts"],
collectCoverage: true,
coverageReporters: ["html", "lcov"],
coverageDirectory: "coverage",
moduleNameMapper: pathsToModuleNameMapper(compilerOptions?.paths || {}, {
prefix: "<rootDir>/",
}),
};

View File

@ -4,6 +4,6 @@ describe("ElectronLogService", () => {
it("sets dev based on electron method", () => {
process.env.ELECTRON_IS_DEV = "1";
const logService = new ElectronLogService();
expect(logService).toEqual(jasmine.objectContaining({ isDev: true }) as any);
expect(logService).toEqual(expect.objectContaining({ isDev: true }) as any);
});
});

0
electron/spec/test.ts Normal file
View File

View File

@ -2,7 +2,8 @@
"extends": "../shared/tsconfig",
"compilerOptions": {
"paths": {
"jslib-common/*": ["../common/src/*"]
"jslib-common/*": ["../common/src/*"],
"jslib-electron/*": ["./src/*"]
}
},
"include": ["src", "spec"],

View File

@ -0,0 +1,3 @@
{
"extends": "./tsconfig.json"
}

18
jest.config.js Normal file
View File

@ -0,0 +1,18 @@
const { pathsToModuleNameMapper } = require("ts-jest/utils");
const { compilerOptions } = require("./tsconfig");
module.exports = {
collectCoverage: true,
coverageReporters: ["html", "lcov"],
coverageDirectory: "coverage",
moduleNameMapper: pathsToModuleNameMapper(compilerOptions?.paths || {}, {
prefix: "<rootDir>/",
}),
projects: [
"<rootDir>/angular/jest.config.js",
"<rootDir>/common/jest.config.js",
"<rootDir>/electron/jest.config.js",
"<rootDir>/node/jest.config.js",
],
};

16
node/jest.config.js Normal file
View File

@ -0,0 +1,16 @@
const { pathsToModuleNameMapper } = require("ts-jest/utils");
const { compilerOptions } = require("./tsconfig");
module.exports = {
preset: "ts-jest",
roots: ["<rootDir>/spec/"],
testMatch: ["**/+(*.)+(spec).+(ts)"],
setupFilesAfterEnv: ["<rootDir>/spec/test.ts"],
collectCoverage: true,
coverageReporters: ["html", "lcov"],
coverageDirectory: "coverage",
moduleNameMapper: pathsToModuleNameMapper(compilerOptions?.paths || {}, {
prefix: "<rootDir>/",
}),
};

Some files were not shown because too many files have changed in this diff Show More