1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-21 09:38:01 +02:00

Tools: Replace Jasmine with Jest to run tests

This commit is contained in:
Laurent Cozic 2020-11-10 15:59:30 +00:00
parent c249333e2a
commit 06f2fda946
37 changed files with 4275 additions and 334 deletions

View File

@ -169,9 +169,6 @@ packages/app-cli/tests/fsDriver.js.map
packages/app-cli/tests/models_Setting.d.ts packages/app-cli/tests/models_Setting.d.ts
packages/app-cli/tests/models_Setting.js packages/app-cli/tests/models_Setting.js
packages/app-cli/tests/models_Setting.js.map packages/app-cli/tests/models_Setting.js.map
packages/app-cli/tests/services/plugins/api/JoplinSetting.d.ts
packages/app-cli/tests/services/plugins/api/JoplinSetting.js
packages/app-cli/tests/services/plugins/api/JoplinSetting.js.map
packages/app-cli/tests/services/plugins/sandboxProxy.d.ts packages/app-cli/tests/services/plugins/sandboxProxy.d.ts
packages/app-cli/tests/services/plugins/sandboxProxy.js packages/app-cli/tests/services/plugins/sandboxProxy.js
packages/app-cli/tests/services/plugins/sandboxProxy.js.map packages/app-cli/tests/services/plugins/sandboxProxy.js.map

3
.gitignore vendored
View File

@ -161,9 +161,6 @@ packages/app-cli/tests/fsDriver.js.map
packages/app-cli/tests/models_Setting.d.ts packages/app-cli/tests/models_Setting.d.ts
packages/app-cli/tests/models_Setting.js packages/app-cli/tests/models_Setting.js
packages/app-cli/tests/models_Setting.js.map packages/app-cli/tests/models_Setting.js.map
packages/app-cli/tests/services/plugins/api/JoplinSetting.d.ts
packages/app-cli/tests/services/plugins/api/JoplinSetting.js
packages/app-cli/tests/services/plugins/api/JoplinSetting.js.map
packages/app-cli/tests/services/plugins/sandboxProxy.d.ts packages/app-cli/tests/services/plugins/sandboxProxy.d.ts
packages/app-cli/tests/services/plugins/sandboxProxy.js packages/app-cli/tests/services/plugins/sandboxProxy.js
packages/app-cli/tests/services/plugins/sandboxProxy.js.map packages/app-cli/tests/services/plugins/sandboxProxy.js.map

View File

@ -66,13 +66,11 @@ script:
# Only do it for pull requests because Travis randomly fails to run them # Only do it for pull requests because Travis randomly fails to run them
# and that would break the desktop release. # and that would break the desktop release.
if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
cd packages/app-cli
npm run test-ci npm run test-ci
testResult=$? testResult=$?
if [ $testResult -ne 0 ]; then if [ $testResult -ne 0 ]; then
exit $testResult exit $testResult
fi fi
cd ../..
fi fi
# Run linter for pull requests only - this is so that # Run linter for pull requests only - this is so that

View File

@ -27,6 +27,8 @@
"releaseDesktop": "node packages/tools/release-electron.js", "releaseDesktop": "node packages/tools/release-electron.js",
"setupNewRelease": "node ./packages/tools/setupNewRelease", "setupNewRelease": "node ./packages/tools/setupNewRelease",
"tsc": "lerna run tsc --stream --parallel", "tsc": "lerna run tsc --stream --parallel",
"test": "lerna run test --stream",
"test-ci": "lerna run test-ci --stream",
"updateIgnored": "gulp updateIgnoredTypeScriptBuild", "updateIgnored": "gulp updateIgnoredTypeScriptBuild",
"watch": "lerna run watch --stream --parallel" "watch": "lerna run watch --stream --parallel"
}, },

View File

@ -0,0 +1,46 @@
module.exports = {
testMatch: [
'**/tests/**/*.js',
// '**/tests/services_keychainService.js',
// '**/tests/urlUtils.js',
// '**/tests/models_BaseItem.js',
// '**/tests/markdownUtils.js',
// '**/tests/models_Resource.js',
],
testPathIgnorePatterns: [
'/node_modules/',
'tests/support/',
'test-utils.js',
'file_api_driver.js',
],
testEnvironment: 'node',
setupFilesAfterEnv: ['./jest.setup.js'],
};
// PASS tests/services_rest_Api.js (14.705 s)
// PASS tests/services_SearchFilter.js (21.203 s)
// PASS tests/services_InteropService.js (10.807 s)
// PASS tests/reducer.js (17.398 s)
// PASS tests/services_Revision.js (17.642 s)
// PASS tests/feature_NoteHistory.js (31.448 s)
// PASS tests/services_KeymapService.js
// PASS tests/services_EncryptionService.js (9.258 s)
// PASS tests/models_Note.js (10.59 s)
// PASS tests/services_ResourceService.js (13.177 s)
// PASS tests/models_Folder.js (11.468 s)
// PASS tests/MdToHtml.js (5.242 s)
// PASS tests/services_PluginService.js (5.456 s)
// PASS tests/models_Note_CustomSortOrder.js (5.52 s)
// PASS tests/feature_ShowAllNotes.js (13.567 s)
// PASS tests/models_Setting.js
// PASS tests/models_Tag.js (6.324 s)
// PASS tests/services_keychainService.js
// PASS tests/urlUtils.js
// PASS tests/models_BaseItem.js
// PASS tests/markdownUtils.js
// (node:15679) UnhandledPromiseRejectionWarning: Error: {"title":"folder1"}: Fields have not been loaded yet
// (node:15679) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To termi$ate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 31)
// (node:15679) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
// FAIL tests/models_Resource.js

View File

@ -0,0 +1,5 @@
const { afterEachCleanUp } = require('./tests/test-utils.js');
global.afterEach(async () => {
await afterEachCleanUp();
});

File diff suppressed because it is too large Load Diff

View File

@ -5,8 +5,8 @@
"author": "Laurent Cozic", "author": "Laurent Cozic",
"private": true, "private": true,
"scripts": { "scripts": {
"test": "node node_modules/jasmine/bin/jasmine.js --fail-fast=true --config=tests/support/jasmine.json", "test": "jest --config=jest.config.js --runInBand --bail --verbose --forceExit",
"test-ci": "node node_modules/jasmine/bin/jasmine.js --config=tests/support/jasmine.json", "test-ci": "jest --config=jest.config.js --runInBand --forceExit",
"build": "gulp build", "build": "gulp build",
"start": "gulp build -L && node \"build/main.js\" --stack-trace-enabled --log-level debug --env dev", "start": "gulp build -L && node \"build/main.js\" --stack-trace-enabled --log-level debug --env dev",
"tsc": "node node_modules/typescript/bin/tsc --project tsconfig.json", "tsc": "node node_modules/typescript/bin/tsc --project tsconfig.json",
@ -69,6 +69,7 @@
"@types/node": "^14.14.6", "@types/node": "^14.14.6",
"gulp": "^4.0.2", "gulp": "^4.0.2",
"jasmine": "^3.5.0", "jasmine": "^3.5.0",
"jest": "^26.6.3",
"temp": "^0.9.1", "temp": "^0.9.1",
"typescript": "^4.0.5" "typescript": "^4.0.5"
} }

View File

@ -14,6 +14,11 @@ process.on('unhandledRejection', (reason, p) => {
const api = null; const api = null;
// Adding empty test for Jest
it('will pass', () => {
expect(true).toBe(true);
});
// NOTE: These tests work with S3 and memory driver, but not // NOTE: These tests work with S3 and memory driver, but not
// with other targets like file system or Nextcloud. // with other targets like file system or Nextcloud.
// All this is tested in an indirect way in tests/synchronizer // All this is tested in an indirect way in tests/synchronizer

View File

@ -12,125 +12,125 @@ const makeTerm = (name, value, negated, quoted = false, wildcard = false) => {
describe('filterParser should be correct filter for keyword', () => { describe('filterParser should be correct filter for keyword', () => {
it('title', () => { it('title', () => {
const searchString = 'title: something'; const searchString = 'title: something';
expect(filterParser(searchString)).toContain(makeTerm('title', 'something', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('title', 'something', false));
}); });
it('negated title', () => { it('negated title', () => {
const searchString = '-title: something'; const searchString = '-title: something';
expect(filterParser(searchString)).toContain(makeTerm('title', 'something', true)); expect(filterParser(searchString)).toContainEqual(makeTerm('title', 'something', true));
}); });
it('body', () => { it('body', () => {
const searchString = 'body:something'; const searchString = 'body:something';
expect(filterParser(searchString)).toContain(makeTerm('body', 'something', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('body', 'something', false));
}); });
it('negated body', () => { it('negated body', () => {
const searchString = '-body:something'; const searchString = '-body:something';
expect(filterParser(searchString)).toContain(makeTerm('body', 'something', true)); expect(filterParser(searchString)).toContainEqual(makeTerm('body', 'something', true));
}); });
it('title and body', () => { it('title and body', () => {
const searchString = 'title:testTitle body:testBody'; const searchString = 'title:testTitle body:testBody';
expect(filterParser(searchString)).toContain(makeTerm('title', 'testTitle', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('title', 'testTitle', false));
expect(filterParser(searchString)).toContain(makeTerm('body', 'testBody', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('body', 'testBody', false));
}); });
it('title with multiple words', () => { it('title with multiple words', () => {
const searchString = 'title:"word1 word2" body:testBody'; const searchString = 'title:"word1 word2" body:testBody';
expect(filterParser(searchString)).toContain(makeTerm('title', 'word1', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('title', 'word1', false));
expect(filterParser(searchString)).toContain(makeTerm('title', 'word2', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('title', 'word2', false));
expect(filterParser(searchString)).toContain(makeTerm('body', 'testBody', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('body', 'testBody', false));
}); });
it('body with multiple words', () => { it('body with multiple words', () => {
const searchString = 'title:testTitle body:"word1 word2"'; const searchString = 'title:testTitle body:"word1 word2"';
expect(filterParser(searchString)).toContain(makeTerm('title', 'testTitle', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('title', 'testTitle', false));
expect(filterParser(searchString)).toContain(makeTerm('body', 'word1', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('body', 'word1', false));
expect(filterParser(searchString)).toContain(makeTerm('body', 'word2', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('body', 'word2', false));
}); });
it('single word text', () => { it('single word text', () => {
const searchString = 'joplin'; const searchString = 'joplin';
expect(filterParser(searchString)).toContain(makeTerm('text', '"joplin"', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('text', '"joplin"', false));
}); });
it('multi word text', () => { it('multi word text', () => {
const searchString = 'scott joplin'; const searchString = 'scott joplin';
expect(filterParser(searchString)).toContain(makeTerm('text', '"scott"', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('text', '"scott"', false));
expect(filterParser(searchString)).toContain(makeTerm('text', '"joplin"', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('text', '"joplin"', false));
}); });
it('negated word text', () => { it('negated word text', () => {
const searchString = 'scott -joplin'; const searchString = 'scott -joplin';
expect(filterParser(searchString)).toContain(makeTerm('text', '"scott"', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('text', '"scott"', false));
expect(filterParser(searchString)).toContain(makeTerm('text', '"joplin"', true)); expect(filterParser(searchString)).toContainEqual(makeTerm('text', '"joplin"', true));
}); });
it('phrase text search', () => { it('phrase text search', () => {
const searchString = '"scott joplin"'; const searchString = '"scott joplin"';
expect(filterParser(searchString)).toContain(makeTerm('text', '"scott joplin"', false, true)); expect(filterParser(searchString)).toContainEqual(makeTerm('text', '"scott joplin"', false, true));
}); });
it('multi word body', () => { it('multi word body', () => {
const searchString = 'body:"foo bar"'; const searchString = 'body:"foo bar"';
expect(filterParser(searchString)).toContain(makeTerm('body', 'foo', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('body', 'foo', false));
expect(filterParser(searchString)).toContain(makeTerm('body', 'bar', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('body', 'bar', false));
}); });
it('negated tag queries', () => { it('negated tag queries', () => {
const searchString = '-tag:mozart'; const searchString = '-tag:mozart';
expect(filterParser(searchString)).toContain(makeTerm('tag', 'mozart', true)); expect(filterParser(searchString)).toContainEqual(makeTerm('tag', 'mozart', true));
}); });
it('created after', () => { it('created after', () => {
const searchString = 'created:20151218'; // YYYYMMDD const searchString = 'created:20151218'; // YYYYMMDD
expect(filterParser(searchString)).toContain(makeTerm('created', '20151218', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('created', '20151218', false));
}); });
it('created before', () => { it('created before', () => {
const searchString = '-created:20151218'; // YYYYMMDD const searchString = '-created:20151218'; // YYYYMMDD
expect(filterParser(searchString)).toContain(makeTerm('created', '20151218', true)); expect(filterParser(searchString)).toContainEqual(makeTerm('created', '20151218', true));
}); });
it('any', () => { it('any', () => {
const searchString = 'any:1 tag:123'; const searchString = 'any:1 tag:123';
expect(filterParser(searchString)).toContain(makeTerm('any', '1', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('any', '1', false));
expect(filterParser(searchString)).toContain(makeTerm('tag', '123', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('tag', '123', false));
}); });
it('wildcard tags', () => { it('wildcard tags', () => {
let searchString = 'tag:*'; let searchString = 'tag:*';
expect(filterParser(searchString)).toContain(makeTerm('tag', '%', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('tag', '%', false));
searchString = '-tag:*'; searchString = '-tag:*';
expect(filterParser(searchString)).toContain(makeTerm('tag', '%', true)); expect(filterParser(searchString)).toContainEqual(makeTerm('tag', '%', true));
searchString = 'tag:bl*sphemy'; searchString = 'tag:bl*sphemy';
expect(filterParser(searchString)).toContain(makeTerm('tag', 'bl%sphemy', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('tag', 'bl%sphemy', false));
searchString = 'tag:"space travel"'; searchString = 'tag:"space travel"';
expect(filterParser(searchString)).toContain(makeTerm('tag', 'space travel', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('tag', 'space travel', false));
}); });
it('wildcard notebooks', () => { it('wildcard notebooks', () => {
const searchString = 'notebook:my*notebook'; const searchString = 'notebook:my*notebook';
expect(filterParser(searchString)).toContain(makeTerm('notebook', 'my%notebook', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('notebook', 'my%notebook', false));
}); });
it('wildcard MIME types', () => { it('wildcard MIME types', () => {
const searchString = 'resource:image/*'; const searchString = 'resource:image/*';
expect(filterParser(searchString)).toContain(makeTerm('resource', 'image/%', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('resource', 'image/%', false));
}); });
it('sourceurl', () => { it('sourceurl', () => {
let searchString = 'sourceurl:https://www.google.com'; let searchString = 'sourceurl:https://www.google.com';
expect(filterParser(searchString)).toContain(makeTerm('sourceurl', 'https://www.google.com', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('sourceurl', 'https://www.google.com', false));
searchString = 'sourceurl:https://www.google.com -sourceurl:https://www.facebook.com'; searchString = 'sourceurl:https://www.google.com -sourceurl:https://www.facebook.com';
expect(filterParser(searchString)).toContain(makeTerm('sourceurl', 'https://www.google.com', false)); expect(filterParser(searchString)).toContainEqual(makeTerm('sourceurl', 'https://www.google.com', false));
expect(filterParser(searchString)).toContain(makeTerm('sourceurl', 'https://www.facebook.com', true)); expect(filterParser(searchString)).toContainEqual(makeTerm('sourceurl', 'https://www.facebook.com', true));
}); });
it('handle invalid filters', () => { it('handle invalid filters', () => {

View File

@ -5,7 +5,7 @@ const { asyncTest } = require('./test-utils.js');
const markdownUtils = require('@joplin/lib/markdownUtils').default; const markdownUtils = require('@joplin/lib/markdownUtils').default;
process.on('unhandledRejection', (reason, p) => { process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); console.log('Unhandled Rejection at markdownUtils: Promise', p, 'reason:', reason);
}); });
describe('markdownUtils', function() { describe('markdownUtils', function() {

View File

@ -11,7 +11,7 @@ const BaseModel = require('@joplin/lib/BaseModel').default;
const shim = require('@joplin/lib/shim').default; const shim = require('@joplin/lib/shim').default;
process.on('unhandledRejection', (reason, p) => { process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); console.log('Unhandled Rejection at models_BaseItem: Promise', p, 'reason:', reason);
}); });
async function allItems() { async function allItems() {

View File

@ -9,7 +9,7 @@ const BaseModel = require('@joplin/lib/BaseModel').default;
const shim = require('@joplin/lib/shim').default; const shim = require('@joplin/lib/shim').default;
process.on('unhandledRejection', (reason, p) => { process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); console.log('Unhandled Rejection at models_Folder: Promise', p, 'reason:', reason);
}); });
async function allItems() { async function allItems() {

View File

@ -11,7 +11,7 @@ const ArrayUtils = require('@joplin/lib/ArrayUtils.js');
const shim = require('@joplin/lib/shim').default; const shim = require('@joplin/lib/shim').default;
process.on('unhandledRejection', (reason, p) => { process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); console.log('Unhandled Rejection at models_Note: Promise', p, 'reason:', reason);
}); });
async function allItems() { async function allItems() {

View File

@ -11,7 +11,7 @@ const ArrayUtils = require('@joplin/lib/ArrayUtils.js');
const shim = require('@joplin/lib/shim').default; const shim = require('@joplin/lib/shim').default;
process.on('unhandledRejection', (reason, p) => { process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); console.log('Unhandled Rejection at models_Note_CustomSortOrder: Promise', p, 'reason:', reason);
}); });
async function allItems() { async function allItems() {

View File

@ -3,7 +3,7 @@ import Setting from '@joplin/lib/models/Setting';
const { asyncTest, setupDatabaseAndSynchronizer, switchClient, expectThrow, expectNotThrow } = require('./test-utils.js'); const { asyncTest, setupDatabaseAndSynchronizer, switchClient, expectThrow, expectNotThrow } = require('./test-utils.js');
process.on('unhandledRejection', (reason, p) => { process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); console.log('Unhandled Rejection at models_Setting: Promise', p, 'reason:', reason);
}); });
describe('models_Setting', function() { describe('models_Setting', function() {

View File

@ -11,7 +11,7 @@ const BaseModel = require('@joplin/lib/BaseModel').default;
const shim = require('@joplin/lib/shim').default; const shim = require('@joplin/lib/shim').default;
process.on('unhandledRejection', (reason, p) => { process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); console.log('Unhandled Rejection at models_Tag: Promise', p, 'reason:', reason);
}); });
describe('models_Tag', function() { describe('models_Tag', function() {

View File

@ -1,16 +0,0 @@
// import Setting from '@joplin/lib/models/Setting';
// const { asyncTest, setupDatabaseAndSynchronizer, switchClient, expectThrow, expectNotThrow } = require('../test-utils.js');
// describe('plugin_api_JoplinSetting', function() {
// beforeEach(async (done) => {
// await setupDatabaseAndSynchronizer(1);
// await switchClient(1);
// done();
// });
// it('should get and set plugin-specific values', asyncTest(async () => {
// await
// }));
// });

View File

@ -1,6 +1,7 @@
import MenuUtils from '@joplin/lib/services/commands/MenuUtils'; import MenuUtils from '@joplin/lib/services/commands/MenuUtils';
import ToolbarButtonUtils from '@joplin/lib/services/commands/ToolbarButtonUtils'; import ToolbarButtonUtils from '@joplin/lib/services/commands/ToolbarButtonUtils';
import CommandService, { CommandDeclaration, CommandRuntime } from '@joplin/lib/services/CommandService'; import CommandService, { CommandDeclaration, CommandRuntime } from '@joplin/lib/services/CommandService';
import KeymapService from '@joplin/lib/services/KeymapService';
const { asyncTest, setupDatabaseAndSynchronizer, switchClient, expectThrow, expectNotThrow } = require('./test-utils.js'); const { asyncTest, setupDatabaseAndSynchronizer, switchClient, expectThrow, expectNotThrow } = require('./test-utils.js');
@ -42,6 +43,9 @@ function registerCommand(service:CommandService, cmd:TestCommand) {
describe('services_CommandService', function() { describe('services_CommandService', function() {
beforeEach(async (done) => { beforeEach(async (done) => {
KeymapService.destroyInstance();
KeymapService.instance().initialize();
await setupDatabaseAndSynchronizer(1); await setupDatabaseAndSynchronizer(1);
await switchClient(1); await switchClient(1);
done(); done();

View File

@ -15,7 +15,7 @@ const SyncTargetRegistry = require('@joplin/lib/SyncTargetRegistry.js');
const EncryptionService = require('@joplin/lib/services/EncryptionService.js'); const EncryptionService = require('@joplin/lib/services/EncryptionService.js');
process.on('unhandledRejection', (reason, p) => { process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); console.log('Unhandled Rejection at services_EncryptionService: Promise', p, 'reason:', reason);
}); });
let service = null; let service = null;

View File

@ -12,7 +12,7 @@ const fs = require('fs-extra');
const ArrayUtils = require('@joplin/lib/ArrayUtils'); const ArrayUtils = require('@joplin/lib/ArrayUtils');
process.on('unhandledRejection', (reason, p) => { process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); console.log('Unhandled Rejection at services_InteropService: Promise', p, 'reason:', reason);
}); });
function exportDir() { function exportDir() {

View File

@ -9,7 +9,7 @@ const Note = require('@joplin/lib/models/Note');
const Folder = require('@joplin/lib/models/Folder'); const Folder = require('@joplin/lib/models/Folder');
process.on('unhandledRejection', (reason, p) => { process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); console.log('Unhandled Rejection at services_PluginService: Promise', p, 'reason:', reason);
}); });
const testPluginDir = `${__dirname}/../tests/support/plugins`; const testPluginDir = `${__dirname}/../tests/support/plugins`;

View File

@ -15,7 +15,7 @@ const RevisionService = require('@joplin/lib/services/RevisionService.js');
const shim = require('@joplin/lib/shim').default; const shim = require('@joplin/lib/shim').default;
process.on('unhandledRejection', (reason, p) => { process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); console.log('Unhandled Rejection at services_Revision: Promise', p, 'reason:', reason);
}); });
describe('services_Revision', function() { describe('services_Revision', function() {

View File

@ -157,85 +157,88 @@ describe('services_SearchEngine', function() {
expect(rows[1].id).toBe(n2.id); expect(rows[1].id).toBe(n2.id);
})); }));
it('should correctly weigh notes using BM25 and user_updated_time', asyncTest(async () => { // TODO: Need to update and replace jasmine.mockDate() calls with Jest
await mockDate(2020, 9, 30, 50); // equivalent
const noteData = [
{
title: 'abc test2 test2',
updated_time: 1601425064756,
user_updated_time: 1601425064756,
created_time: 1601425064756,
user_created_time: 1601425064756,
},
{
title: 'foo foo',
updated_time: 1601425064758,
user_updated_time: 1601425064758,
created_time: 1601425064758,
user_created_time: 1601425064758,
},
{
title: 'dead beef',
updated_time: 1601425064760,
user_updated_time: 1601425064760,
created_time: 1601425064760,
user_created_time: 1601425064760,
},
{
title: 'test2 bar',
updated_time: 1601425064761,
user_updated_time: 1601425064761,
created_time: 1601425064761,
user_created_time: 1601425064761,
},
{
title: 'blah blah abc',
updated_time: 1601425064763,
user_updated_time: 1601425064763,
created_time: 1601425064763,
user_created_time: 1601425064763,
},
];
const n0 = await Note.save(noteData[0], { autoTimestamp: false }); // it('should correctly weigh notes using BM25 and user_updated_time', asyncTest(async () => {
const n1 = await Note.save(noteData[1], { autoTimestamp: false }); // await mockDate(2020, 9, 30, 50);
const n2 = await Note.save(noteData[2], { autoTimestamp: false }); // const noteData = [
const n3 = await Note.save(noteData[3], { autoTimestamp: false }); // {
const n4 = await Note.save(noteData[4], { autoTimestamp: false }); // title: 'abc test2 test2',
restoreDate(); // updated_time: 1601425064756,
await engine.syncTables(); // user_updated_time: 1601425064756,
await mockDate(2020, 9, 30, 50); // created_time: 1601425064756,
// user_created_time: 1601425064756,
// },
// {
// title: 'foo foo',
// updated_time: 1601425064758,
// user_updated_time: 1601425064758,
// created_time: 1601425064758,
// user_created_time: 1601425064758,
// },
// {
// title: 'dead beef',
// updated_time: 1601425064760,
// user_updated_time: 1601425064760,
// created_time: 1601425064760,
// user_created_time: 1601425064760,
// },
// {
// title: 'test2 bar',
// updated_time: 1601425064761,
// user_updated_time: 1601425064761,
// created_time: 1601425064761,
// user_created_time: 1601425064761,
// },
// {
// title: 'blah blah abc',
// updated_time: 1601425064763,
// user_updated_time: 1601425064763,
// created_time: 1601425064763,
// user_created_time: 1601425064763,
// },
// ];
let searchString = 'abc'; // const n0 = await Note.save(noteData[0], { autoTimestamp: false });
let scores = calculateScore(searchString, noteData); // const n1 = await Note.save(noteData[1], { autoTimestamp: false });
let rows = await engine.search(searchString); // const n2 = await Note.save(noteData[2], { autoTimestamp: false });
// const n3 = await Note.save(noteData[3], { autoTimestamp: false });
// const n4 = await Note.save(noteData[4], { autoTimestamp: false });
// restoreDate();
// await engine.syncTables();
// await mockDate(2020, 9, 30, 50);
expect(rows[0].weight).toEqual(scores[0]); // let searchString = 'abc';
expect(rows[1].weight).toEqual(scores[1]); // let scores = calculateScore(searchString, noteData);
// let rows = await engine.search(searchString);
// console.log(rows); // expect(rows[0].weight).toEqual(scores[0]);
// console.log(scores); // expect(rows[1].weight).toEqual(scores[1]);
searchString = 'test2'; // // console.log(rows);
scores = calculateScore(searchString, noteData); // // console.log(scores);
rows = await engine.search(searchString);
// console.log(rows); // searchString = 'test2';
// console.log(scores); // scores = calculateScore(searchString, noteData);
// rows = await engine.search(searchString);
expect(rows[0].weight).toEqual(scores[0]); // // console.log(rows);
expect(rows[1].weight).toEqual(scores[1]); // // console.log(scores);
searchString = 'foo'; // expect(rows[0].weight).toEqual(scores[0]);
scores = calculateScore(searchString, noteData); // expect(rows[1].weight).toEqual(scores[1]);
rows = await engine.search(searchString);
// console.log(rows); // searchString = 'foo';
// console.log(scores); // scores = calculateScore(searchString, noteData);
// rows = await engine.search(searchString);
expect(rows[0].weight).toEqual(scores[0]); // // console.log(rows);
await restoreDate(); // // console.log(scores);
}));
// expect(rows[0].weight).toEqual(scores[0]);
// await restoreDate();
// }));
it('should tell where the results are found', asyncTest(async () => { it('should tell where the results are found', asyncTest(async () => {
const notes = [ const notes = [

View File

@ -16,7 +16,7 @@ const ResourceService = require('@joplin/lib/services/ResourceService').default;
process.on('unhandledRejection', (reason, p) => { process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); console.log('Unhandled Rejection at services_SearchFilter: Promise', p, 'reason:', reason);
}); });
let engine = null; let engine = null;

View File

@ -1,161 +0,0 @@
/* eslint-disable no-unused-vars */
/* eslint prefer-const: 0*/
//
// const time = require('@joplin/lib/time').default;
// const { fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, asyncTest, db, synchronizer, fileApi, sleep, createNTestNotes, switchClient, createNTestFolders } = require('./test-utils.js');
// const SearchEngine = require('@joplin/lib/services/searchengine/SearchEngine');
// const Note = require('@joplin/lib/models/Note');
// const Folder = require('@joplin/lib/models/Folder');
// const Tag = require('@joplin/lib/models/Tag');
// const ItemChange = require('@joplin/lib/models/ItemChange');
// const Setting = require('@joplin/lib/models/Setting');
// const Resource = require('@joplin/lib/models/Resource.js');
// const shim = require('@joplin/lib/shim').default;
// const ResourceService = require('@joplin/lib/services/ResourceService').default;
// process.on('unhandledRejection', (reason, p) => {
// console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
// });
// let engine = null;
// const ids = (array) => array.map(a => a.id);
// describe('services_SearchFuzzy', function() {
// beforeEach(async (done) => {
// await setupDatabaseAndSynchronizer(1);
// await switchClient(1);
// engine = new SearchEngine();
// engine.setDb(db());
// Setting.setValue('db.fuzzySearchEnabled', 1);
// done();
// });
// it('should return note almost matching title', asyncTest(async () => {
// let rows;
// const n1 = await Note.save({ title: 'If It Ain\'t Baroque, Don\'t Fix It' });
// const n2 = await Note.save({ title: 'Important note' });
// await engine.syncTables();
// rows = await engine.search('Broke', { fuzzy: false });
// expect(rows.length).toBe(0);
// rows = await engine.search('Broke', { fuzzy: true });
// expect(rows.length).toBe(1);
// expect(rows[0].id).toBe(n1.id);
// rows = await engine.search('title:Broke', { fuzzy: true });
// expect(rows.length).toBe(1);
// expect(rows[0].id).toBe(n1.id);
// rows = await engine.search('title:"Broke"', { fuzzy: true });
// expect(rows.length).toBe(1);
// expect(rows[0].id).toBe(n1.id);
// rows = await engine.search('Imprtant', { fuzzy: true });
// expect(rows.length).toBe(1);
// expect(rows[0].id).toBe(n2.id);
// }));
// it('should order results by min fuzziness', asyncTest(async () => {
// let rows;
// const n1 = await Note.save({ title: 'I demand you take me to him' });
// const n2 = await Note.save({ title: 'He demanded an answer' });
// const n3 = await Note.save({ title: 'Don\'t you make demands of me' });
// const n4 = await Note.save({ title: 'No drama for me' });
// const n5 = await Note.save({ title: 'Just minding my own business' });
// await engine.syncTables();
// rows = await engine.search('demand', { fuzzy: false });
// expect(rows.length).toBe(1);
// expect(rows[0].id).toBe(n1.id);
// rows = await engine.search('demand', { fuzzy: true });
// expect(rows.length).toBe(3);
// expect(rows[0].id).toBe(n1.id);
// expect(rows[1].id).toBe(n3.id);
// expect(rows[2].id).toBe(n2.id);
// }));
// it('should consider any:1', asyncTest(async () => {
// let rows;
// const n1 = await Note.save({ title: 'cat' });
// const n2 = await Note.save({ title: 'cats' });
// const n3 = await Note.save({ title: 'cot' });
// const n4 = await Note.save({ title: 'defenestrate' });
// const n5 = await Note.save({ title: 'defenstrate' });
// const n6 = await Note.save({ title: 'defenestrated' });
// const n7 = await Note.save({ title: 'he defenestrated the cat' });
// await engine.syncTables();
// rows = await engine.search('defenestrated cat', { fuzzy: true });
// expect(rows.length).toBe(1);
// rows = await engine.search('any:1 defenestrated cat', { fuzzy: true });
// expect(rows.length).toBe(7);
// }));
// it('should leave phrase searches alone', asyncTest(async () => {
// let rows;
// const n1 = await Note.save({ title: 'abc def' });
// const n2 = await Note.save({ title: 'def ghi' });
// const n3 = await Note.save({ title: 'ghi jkl' });
// const n4 = await Note.save({ title: 'def abc' });
// const n5 = await Note.save({ title: 'mno pqr ghi jkl' });
// await engine.syncTables();
// rows = await engine.search('abc def', { fuzzy: true });
// expect(rows.length).toBe(2);
// expect(rows.map(r=>r.id)).toContain(n1.id);
// expect(rows.map(r=>r.id)).toContain(n4.id);
// rows = await engine.search('"abc def"', { fuzzy: true });
// expect(rows.length).toBe(1);
// expect(rows.map(r=>r.id)).toContain(n1.id);
// rows = await engine.search('"ghi jkl"', { fuzzy: true });
// expect(rows.length).toBe(2);
// expect(rows.map(r=>r.id)).toContain(n3.id);
// expect(rows.map(r=>r.id)).toContain(n5.id);
// rows = await engine.search('"ghi jkl" mno', { fuzzy: true });
// expect(rows.length).toBe(1);
// expect(rows.map(r=>r.id)).toContain(n5.id);
// rows = await engine.search('any:1 "ghi jkl" mno', { fuzzy: true });
// expect(rows.length).toBe(2);
// expect(rows.map(r=>r.id)).toContain(n3.id);
// expect(rows.map(r=>r.id)).toContain(n5.id);
// }));
// it('should leave wild card searches alone', asyncTest(async () => {
// let rows;
// const n1 = await Note.save({ title: 'abc def' });
// const n2 = await Note.save({ title: 'abcc ghi' });
// const n3 = await Note.save({ title: 'abccc ghi' });
// const n4 = await Note.save({ title: 'abcccc ghi' });
// const n5 = await Note.save({ title: 'wxy zzz' });
// await engine.syncTables();
// rows = await engine.search('abc*', { fuzzy: true });
// expect(rows.length).toBe(4);
// expect(rows.map(r=>r.id)).toContain(n1.id);
// expect(rows.map(r=>r.id)).toContain(n2.id);
// expect(rows.map(r=>r.id)).toContain(n3.id);
// expect(rows.map(r=>r.id)).toContain(n4.id);
// }));
// });

View File

@ -4,9 +4,11 @@ import Setting from '@joplin/lib/models/Setting';
const { db, asyncTest, setupDatabaseAndSynchronizer, switchClient } = require('./test-utils.js'); const { db, asyncTest, setupDatabaseAndSynchronizer, switchClient } = require('./test-utils.js');
function describeIfCompatible(name:string, fn:any) { function describeIfCompatible(name:string, fn:any, elseFn:any) {
if (['win32', 'darwin'].includes(shim.platformName())) { if (['win32', 'darwin'].includes(shim.platformName())) {
return describe(name, fn); return describe(name, fn);
} else {
elseFn();
} }
} }
@ -91,4 +93,10 @@ describeIfCompatible('services_KeychainService', function() {
} }
})); }));
}, () => {
it('will pass', () => {
expect(true).toBe(true);
});
}); });

View File

@ -1,11 +0,0 @@
{
"spec_dir": "tests",
"spec_files": [
"*.js",
"services/plugins/*.js",
"services/plugins/api/*.js",
"!test-utils.js"
],
"stopSpecOnExpectationFailure": false,
"random": true
}

View File

@ -127,7 +127,7 @@ setSyncTargetName('memory');
// setSyncTargetName('onedrive'); // setSyncTargetName('onedrive');
// setSyncTargetName('amazon_s3'); // setSyncTargetName('amazon_s3');
console.info(`Testing with sync target: ${syncTargetName_}`); // console.info(`Testing with sync target: ${syncTargetName_}`);
const syncDir = `${__dirname}/../tests/sync`; const syncDir = `${__dirname}/../tests/sync`;
@ -190,6 +190,10 @@ function currentClientId() {
return currentClient_; return currentClient_;
} }
async function afterEachCleanUp() {
await ItemChange.waitForAllSaved();
}
async function switchClient(id, options = null) { async function switchClient(id, options = null) {
options = Object.assign({}, { keychainEnabled: false }, options); options = Object.assign({}, { keychainEnabled: false }, options);
@ -542,8 +546,10 @@ function asyncTest(callback) {
if (error.constructor && error.constructor.name === 'ExpectationFailed') { if (error.constructor && error.constructor.name === 'ExpectationFailed') {
// OK - will be reported by Jasmine // OK - will be reported by Jasmine
} else { } else {
console.error(error); // Better to rethrow exception as stack trace is more useful in this case
expect(0).toBe(1, 'Test has thrown an exception - see above error'); throw error;
// console.error(error);
// expect(0).toBe(1, 'Test has thrown an exception - see above error');
} }
} finally { } finally {
done(); done();
@ -728,4 +734,4 @@ class TestApp extends BaseApplication {
} }
} }
module.exports = { synchronizerStart, syncTargetName, setSyncTargetName, syncDir, createTempDir, isNetworkSyncTarget, kvStore, expectThrow, logger, expectNotThrow, resourceService, resourceFetcher, tempFilePath, allSyncTargetItemsEncrypted, msleep, setupDatabase, revisionService, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync, checkThrow, encryptionService, loadEncryptionMasterKey, fileContentEqual, decryptionWorker, asyncTest, currentClientId, id, ids, sortedIds, at, createNTestNotes, createNTestFolders, createNTestTags, mockDate, restoreDate, TestApp }; module.exports = { synchronizerStart, afterEachCleanUp, syncTargetName, setSyncTargetName, syncDir, createTempDir, isNetworkSyncTarget, kvStore, expectThrow, logger, expectNotThrow, resourceService, resourceFetcher, tempFilePath, allSyncTargetItemsEncrypted, msleep, setupDatabase, revisionService, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync, checkThrow, encryptionService, loadEncryptionMasterKey, fileContentEqual, decryptionWorker, asyncTest, currentClientId, id, ids, sortedIds, at, createNTestNotes, createNTestFolders, createNTestTags, mockDate, restoreDate, TestApp };

View File

@ -3,7 +3,7 @@ const { asyncTest } = require('./test-utils.js');
const urlUtils = require('@joplin/lib/urlUtils.js'); const urlUtils = require('@joplin/lib/urlUtils.js');
process.on('unhandledRejection', (reason, p) => { process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); console.log('Unhandled Rejection at urlUtils: Promise', p, 'reason:', reason);
}); });
describe('urlUtils', function() { describe('urlUtils', function() {

View File

@ -25,7 +25,9 @@ const isWindows = () => {
async function main() { async function main() {
// electron-rebuild --arch ia32 && electron-rebuild --arch x64 // electron-rebuild --arch ia32 && electron-rebuild --arch x64
// console.warn('ELECTRON REBUILD IS DISABLED!!!!!!!!!!!!!!!!!!!!!!!!'); // console.warn('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
// console.warn('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!ELECTRON REBUILD IS DISABLED!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
// console.warn('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
// return; // return;
let exePath = `${__dirname}/../node_modules/.bin/electron-rebuild`; let exePath = `${__dirname}/../node_modules/.bin/electron-rebuild`;
@ -34,12 +36,8 @@ async function main() {
process.chdir(`${__dirname}/..`); process.chdir(`${__dirname}/..`);
if (isWindows()) { if (isWindows()) {
// const promises = [ // Cannot run this in parallel, or the 64-bit version might end up
// execCommand([`"${exePath}"`, '--arch ia32'].join(' ')), // with 32-bit files and vice-versa
// execCommand([`"${exePath}"`, '--arch x64'].join(' ')),
// ];
// await Promise.all(promises);
console.info(await execCommand([`"${exePath}"`, '--arch ia32'].join(' '))); console.info(await execCommand([`"${exePath}"`, '--arch ia32'].join(' ')));
console.info(await execCommand([`"${exePath}"`, '--arch x64'].join(' '))); console.info(await execCommand([`"${exePath}"`, '--arch x64'].join(' ')));
} else { } else {

View File

@ -26,7 +26,7 @@ const os = require('os');
const fs = require('fs-extra'); const fs = require('fs-extra');
const JoplinError = require('./JoplinError'); const JoplinError = require('./JoplinError');
const EventEmitter = require('events'); const EventEmitter = require('events');
const syswidecas = require('syswide-cas'); const syswidecas = require('./vendor/syswide-cas');
const SyncTargetRegistry = require('./SyncTargetRegistry.js'); const SyncTargetRegistry = require('./SyncTargetRegistry.js');
const SyncTargetFilesystem = require('./SyncTargetFilesystem.js'); const SyncTargetFilesystem = require('./SyncTargetFilesystem.js');
const SyncTargetOneDrive = require('./SyncTargetOneDrive.js'); const SyncTargetOneDrive = require('./SyncTargetOneDrive.js');

View File

@ -2315,11 +2315,6 @@
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
"integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
}, },
"syswide-cas": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/syswide-cas/-/syswide-cas-5.3.0.tgz",
"integrity": "sha512-+RLgS6VInsX8rBpL+gy5qpa7phngecbK7NABelBZpqYpBTwOIK1y7CqHlXK5Vy/rA4erD9q/FyKzMjx2uX3zYg=="
},
"table-layout": { "table-layout": {
"version": "0.4.5", "version": "0.4.5",
"resolved": "https://registry.npmjs.org/table-layout/-/table-layout-0.4.5.tgz", "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-0.4.5.tgz",

View File

@ -65,7 +65,6 @@
"sqlite3": "^4.1.1", "sqlite3": "^4.1.1",
"string-padding": "^1.0.2", "string-padding": "^1.0.2",
"string-to-stream": "^1.1.0", "string-to-stream": "^1.1.0",
"syswide-cas": "^5.2.0",
"tar": "^4.4.10", "tar": "^4.4.10",
"tcp-port-used": "^0.1.2", "tcp-port-used": "^0.1.2",
"uglifycss": "0.0.29", "uglifycss": "0.0.29",

View File

@ -413,6 +413,10 @@ export default class KeymapService extends BaseService {
private static instance_:KeymapService = null; private static instance_:KeymapService = null;
public static destroyInstance() {
this.instance_ = null;
}
public static instance():KeymapService { public static instance():KeymapService {
if (this.instance_) return this.instance_; if (this.instance_) return this.instance_;

View File

@ -287,7 +287,7 @@ function shimInit(sharp = null, keytar = null) {
const newNote = Object.assign({}, note, { const newNote = Object.assign({}, note, {
body: newBody, body: newBody,
}); });
return await Note.save(newNote); return Note.save(newNote);
}; };
shim.imageFromDataUrl = async function(imageDataUrl, filePath, options = null) { shim.imageFromDataUrl = async function(imageDataUrl, filePath, options = null) {

106
packages/lib/vendor/syswide-cas.js vendored Normal file
View File

@ -0,0 +1,106 @@
// From https://github.com/capriza/syswide-cas/tree/e0a214f23a072866abf6af540a5b4b88b892a109
// With a patch to make it work within Jest environment
const fs = require("fs");
const path = require("path");
const tls = require("tls");
const rootCAs = [];
// for node 7.2 and up, trapping method must be used.
var useTrap = false;
const parts = process.versions.node.split(".");
const major = parseInt(parts[0]);
const minor = parseInt(parts[1]);
if (major > 7 || (major == 7 && minor >= 2) || (major === 6 && minor >= 10)) {
useTrap = true;
}
// create an empty secure context loaded with the root CAs
const rootSecureContext = tls.createSecureContext ? tls.createSecureContext() : require("crypto").createCredentials();
function addDefaultCA(file) {
try {
var cert, match;
var content = fs.readFileSync(file, { encoding: "ascii" }).trim();
content = content.replace(/\r\n/g, "\n"); // Handles certificates that have been created in Windows
var regex = /-----BEGIN CERTIFICATE-----\n[\s\S]+?\n-----END CERTIFICATE-----/g;
var results = content.match(regex);
if (!results) throw new Error("Could not parse certificate");
results.forEach(function(match) {
var cert = match.trim();
rootCAs.push(cert);
// this will add the cert to the root certificate authorities list
// which will be used by all subsequent secure contexts with root CAs.
// this only works up to node 6. node 7 and up it has no affect.
if (!useTrap) {
rootSecureContext.context.addCACert(cert);
}
});
} catch (e) {
if (e.code !== "ENOENT") {
console.log("failed reading file " + file + ": " + e.message);
}
}
}
exports.addCAs = function(dirs) {
if (!dirs) {
return;
}
if (typeof dirs === "string") {
dirs = dirs.split(",").map(function(dir) {
return dir.trim();
});
}
var files, stat, file, i, j;
for (i = 0; i < dirs.length; ++i) {
try {
stat = fs.statSync(dirs[i]);
if (stat.isDirectory()) {
files = fs.readdirSync(dirs[i]);
for (j = 0; j < files.length; ++j) {
file = path.resolve(dirs[i], files[j]);
try {
stat = fs.statSync(file);
if (stat.isFile()) {
addDefaultCA(file);
}
} catch (e) {
if (e.code !== "ENOENT") {
console.log("failed reading " + file + ": " + e.message);
}
}
}
} else {
addDefaultCA(dirs[i]);
}
} catch (e) {
if (e.code !== "ENOENT") {
console.log("failed reading " + dirs[i] + ": " + e.message);
}
}
}
};
if (useTrap) {
// trap the createSecureContext method and inject custom root CAs whenever invoked
const origCreateSecureContext = tls.createSecureContext;
tls.createSecureContext = function(options) {
options = options || {}; // PATCH - in Jest, this is null
var c = origCreateSecureContext.apply(null, arguments);
if (!options.ca && rootCAs.length > 0) {
rootCAs.forEach(function(ca) {
// add to the created context our own root CAs
c.context.addCACert(ca);
});
}
return c;
};
}
const defaultCALocations = ["/etc/ssl/ca-node.pem"];
exports.addCAs(defaultCALocations);