diff --git a/packages/lib/fsDriver.test.ts b/packages/lib/fsDriver.test.ts
index 5984679ed0..6975e64eca 100644
--- a/packages/lib/fsDriver.test.ts
+++ b/packages/lib/fsDriver.test.ts
@@ -9,7 +9,7 @@ const windowsPartitionLetter = __filename[0];
// /tmp/file.txt to {partition}:\tmp\file.txt
function platformPath(path: string) {
if (shim.isWindows()) {
- return `${windowsPartitionLetter}:${path.replace(/\//g, '\\')}`;
+ return `${windowsPartitionLetter.toLowerCase()}:${path.replace(/\//g, '\\')}`;
} else {
return path;
}
diff --git a/packages/lib/services/rest/Api.test.ts b/packages/lib/services/rest/Api.test.ts
index 8fc6386f26..a1aca31466 100644
--- a/packages/lib/services/rest/Api.test.ts
+++ b/packages/lib/services/rest/Api.test.ts
@@ -12,6 +12,9 @@ import ResourceService from '../../services/ResourceService';
import SearchEngine from '../search/SearchEngine';
const { MarkupToHtml } = require('@joplin/renderer');
import { NoteEntity, ResourceEntity } from '../database/types';
+import { toFileProtocolPath } from '@joplin/utils/path';
+import { join } from 'path';
+import { htmlentities } from '@joplin/utils/html';
const createFolderForPagination = async (num: number, time: number) => {
await Folder.save({
@@ -512,10 +515,11 @@ describe('services/rest/Api', () => {
let response = null;
const f = await Folder.save({ title: 'pdf test1' });
+ const url = toFileProtocolPath(join(supportDir, 'welcome.pdf'));
response = await api.route(RequestMethod.POST, 'notes', null, JSON.stringify({
title: 'testing PDF embeds',
parent_id: f.id,
- body_html: `
`,
+ body_html: `
`,
}));
const resources = await Resource.all();
diff --git a/packages/lib/urlUtils.test.js b/packages/lib/urlUtils.test.js
index 8d53620088..2b6c349401 100644
--- a/packages/lib/urlUtils.test.js
+++ b/packages/lib/urlUtils.test.js
@@ -57,20 +57,33 @@ describe('urlUtils', () => {
[
'file:///home/builder/.config/joplindev-desktop/profile-owmhbsat/resources/4a12670298dd46abbb140ffc8a10b583.md',
'/home/builder/.config/joplindev-desktop/profile-owmhbsat/resources',
+ 'posix',
{ itemId: '4a12670298dd46abbb140ffc8a10b583', hash: '' },
],
[
'file:///home/builder/.config/joplindev-desktop/profile-owmhbsat/resources/4a12670298dd46abbb140ffc8a10b583.md5#foo',
'/home/builder/.config/joplindev-desktop/profile-owmhbsat/resources',
+ 'posix',
{ itemId: '4a12670298dd46abbb140ffc8a10b583', hash: 'foo' },
],
[
'file:///home/builder/.config/joplindev-desktop/profile-owmhbsat/resources/4a12670298dd46abbb140ffc8a10b583.png?t=12345',
'/home/builder/.config/joplindev-desktop/profile-owmhbsat/resources',
+ 'posix',
{ itemId: '4a12670298dd46abbb140ffc8a10b583', hash: '' },
],
- ])('should detect resource file URLs', (url, resourceDir, expected) => {
- expect(urlUtils.parseResourceUrl(urlUtils.fileUrlToResourceUrl(url, resourceDir))).toMatchObject(expected);
+ [
+ 'file:///C:/Users/Test/.config/joplin-desktop/profile-owmhbsat/resources/a1234567890123456789012345678901.png?t=12345',
+ 'C:\\Users\\Test\\.config\\joplin-desktop\\profile-owmhbsat\\resources',
+ 'win32',
+ { itemId: 'a1234567890123456789012345678901', hash: '' },
+ ],
+ ])('should detect resource file URLs (case %#)', (url, resourceDir, os, expected) => {
+ expect(
+ urlUtils.parseResourceUrl(
+ urlUtils.fileUrlToResourceUrl(url, resourceDir, os),
+ ),
+ ).toMatchObject(expected);
});
it('should extract resource URLs', (async () => {
diff --git a/packages/lib/urlUtils.ts b/packages/lib/urlUtils.ts
index 6125bde49a..4c56cc224a 100644
--- a/packages/lib/urlUtils.ts
+++ b/packages/lib/urlUtils.ts
@@ -72,8 +72,8 @@ export const parseResourceUrl = (url: string) => {
};
};
-export const fileUrlToResourceUrl = (fileUrl: string, resourceDir: string) => {
- let resourceDirUrl = toFileProtocolPath(resourceDir);
+export const fileUrlToResourceUrl = (fileUrl: string, resourceDir: string, os: string|null = null) => {
+ let resourceDirUrl = toFileProtocolPath(resourceDir, os);
if (!resourceDirUrl.endsWith('/')) {
resourceDirUrl += '/';
}
diff --git a/packages/lib/utils/resolvePathWithinDir.test.ts b/packages/lib/utils/resolvePathWithinDir.test.ts
index c6a08953ac..8d60519f1a 100644
--- a/packages/lib/utils/resolvePathWithinDir.test.ts
+++ b/packages/lib/utils/resolvePathWithinDir.test.ts
@@ -1,3 +1,4 @@
+import { posix, win32 } from 'node:path';
import resolvePathWithinDir from './resolvePathWithinDir';
describe('resolvePathWithinDir', () => {
@@ -23,16 +24,16 @@ describe('resolvePathWithinDir', () => {
];
for (const testCase of testCases) {
- expect(resolvePathWithinDir(testCase.baseDir, testCase.path, false)).toBe(testCase.expected);
+ expect(resolvePathWithinDir(testCase.baseDir, testCase.path, posix)).toBe(testCase.expected);
}
});
test('should return correct values for Windows-style paths', () => {
- expect(resolvePathWithinDir('C:\\a\\test\\path', 'C:\\a\\test\\path\\2', true)).toBe('C:\\a\\test\\path\\2');
- expect(resolvePathWithinDir('C:\\\\a\\test\\path', '.\\path\\2', true)).toBe('C:\\a\\test\\path\\path\\2');
- expect(resolvePathWithinDir('C:\\a\\test\\path', '..\\path\\2', true)).toBe('C:\\a\\test\\path\\2');
- expect(resolvePathWithinDir('C:\\a\\test\\path', '..\\2', true)).toBe(null);
- expect(resolvePathWithinDir('D:\\a\\test\\path', 'C:\\a\\test\\path\\2', true)).toBe(null);
- expect(resolvePathWithinDir('\\a\\test\\path', 'D:\\a\\test\\path\\2', true)).toBe(null);
+ expect(resolvePathWithinDir('C:\\a\\test\\path', 'C:\\a\\test\\path\\2', win32)).toBe('C:\\a\\test\\path\\2');
+ expect(resolvePathWithinDir('C:\\\\a\\test\\path', '.\\path\\2', win32)).toBe('C:\\a\\test\\path\\path\\2');
+ expect(resolvePathWithinDir('C:\\a\\test\\path', '..\\path\\2', win32)).toBe('C:\\a\\test\\path\\2');
+ expect(resolvePathWithinDir('C:\\a\\test\\path', '..\\2', win32)).toBe(null);
+ expect(resolvePathWithinDir('D:\\a\\test\\path', 'C:\\a\\test\\path\\2', win32)).toBe(null);
+ expect(resolvePathWithinDir('\\a\\test\\path', 'D:\\a\\test\\path\\2', win32)).toBe(null);
});
});
diff --git a/packages/lib/utils/resolvePathWithinDir.ts b/packages/lib/utils/resolvePathWithinDir.ts
index be32c47f11..7e2cc45df0 100644
--- a/packages/lib/utils/resolvePathWithinDir.ts
+++ b/packages/lib/utils/resolvePathWithinDir.ts
@@ -12,13 +12,8 @@ const resolvePathWithinDir = (
baseDir: string, relativePath: string,
// For testing
- forceWin32Paths?: boolean,
+ pathModule = path,
) => {
- let pathModule = path;
- if (forceWin32Paths === true) {
- pathModule = path.win32;
- }
-
let resolvedBaseDir = pathModule.resolve(baseDir);
const resolvedPath = pathModule.resolve(baseDir, relativePath);
diff --git a/packages/server/src/db.migrations.test.ts b/packages/server/src/db.migrations.test.ts
index a5e2d09cdd..bf22dc91e1 100644
--- a/packages/server/src/db.migrations.test.ts
+++ b/packages/server/src/db.migrations.test.ts
@@ -10,8 +10,12 @@ async function dbSchemaSnapshot(db: DbConnection): Promise {
describe('db.migrations', () => {
+ let testIndex = 0;
beforeEach(async () => {
- await beforeAllDb('db.migrations', { autoMigrate: false });
+ // Use `beforeAllDb` in `beforeEach` to ensure each test has its own database.
+ // To work around file locking issues on Windows, each test needs its own database instance:
+ const databaseKey = `db.migrations.${testIndex ++}`;
+ await beforeAllDb(databaseKey, { autoMigrate: false });
await beforeEachDb();
});
diff --git a/packages/server/src/db.replication.test.ts b/packages/server/src/db.replication.test.ts
index 60ae7111b7..270fe8953d 100644
--- a/packages/server/src/db.replication.test.ts
+++ b/packages/server/src/db.replication.test.ts
@@ -21,8 +21,12 @@ const event2 = {
id: eventId2,
};
+let testIndex = 0;
const beforeTest = async (envValues: Record = null) => {
- await beforeAllDb('db.replication', envValues ? { envValues } : null);
+ // Use `beforeAllDb` in `beforeEach` to ensure each test has its own database.
+ // To work around file locking issues on Windows, each test needs its own database instance:
+ const databaseKey = `db.replication.${testIndex ++}`;
+ await beforeAllDb(databaseKey, envValues ? { envValues } : null);
await beforeEachDb();
};
@@ -32,6 +36,10 @@ const afterTest = async () => {
describe('db.replication', () => {
+ afterEach(async () => {
+ await afterTest();
+ });
+
it('should reconnect a database', async () => {
if (getDatabaseClientType() === DatabaseConfigClient.PostgreSQL) return;
@@ -57,13 +65,13 @@ describe('db.replication', () => {
expect(results.length).toBe(2);
expect([results[0].id, results[1].id].sort()).toEqual([eventId1, eventId2]);
}
-
- await afterTest();
});
it('should manually sync an SQLite slave instance', async () => {
if (getDatabaseClientType() === DatabaseConfigClient.PostgreSQL) return;
+ await beforeTest();
+
const masterConfig: DatabaseConfig = {
client: DatabaseConfigClient.SQLite,
name: `${packageRootDir}/db-master-test.sqlite`,
@@ -139,8 +147,6 @@ describe('db.replication', () => {
expect(result.items.length).toBe(1);
expect(result.items[0].type).toBe(ChangeType.Update);
-
- await afterTest();
});
});
diff --git a/packages/tools/checkLibPaths.test.ts b/packages/tools/checkLibPaths.test.ts
index 6d5e5ce500..7c56e59aac 100644
--- a/packages/tools/checkLibPaths.test.ts
+++ b/packages/tools/checkLibPaths.test.ts
@@ -29,7 +29,7 @@ describe('checkLibPaths', () => {
for (const testCase of testCases) {
const [expected, input] = testCase;
const actual = findInvalidImportPaths(__dirname, input.split('\n').map(l => l.trim()).join('\n'));
- expect(actual.length).toBe(expected);
+ expect(actual).toHaveLength(expected);
}
});
diff --git a/packages/tools/checkLibPaths.ts b/packages/tools/checkLibPaths.ts
index d811ba2af0..1a9ee8467a 100644
--- a/packages/tools/checkLibPaths.ts
+++ b/packages/tools/checkLibPaths.ts
@@ -4,6 +4,7 @@ import { readFile } from 'fs-extra';
import { normalize } from 'path';
import yargs = require('yargs');
import { dirname } from './tool-utils';
+import { toForwardSlashes } from '@joplin/utils/path';
export const findInvalidImportPaths = (baseDir: string, fileContent: string): string[] => {
const output: string[] = [];
@@ -26,7 +27,7 @@ export const findInvalidImportPaths = (baseDir: string, fileContent: string): st
const matches = regex.exec(fileContent);
if (!matches) break;
const [line, packagePath] = matches;
- const fullPath = normalize(`${baseDir}/${packagePath}`);
+ const fullPath = toForwardSlashes(normalize(`${baseDir}/${packagePath}`));
if (fullPath.includes('packages/lib/') || fullPath.includes('packages/renderer/')) output.push(line);
}
diff --git a/packages/transcribe/snapshot-resolver.js b/packages/transcribe/snapshot-resolver.js
index 187e559e99..470deafd37 100644
--- a/packages/transcribe/snapshot-resolver.js
+++ b/packages/transcribe/snapshot-resolver.js
@@ -4,7 +4,7 @@ const path = require('path');
module.exports = {
resolveSnapshotPath: (testPath, snapshotExtension) => {
const srcPath = testPath
- .replace(/dist\/src\//, 'src/')
+ .replace(/dist[/\\]src[/\\]/, 'src/')
.replace(/\.js$/, '');
const snapshotPath = path.join(
@@ -28,5 +28,6 @@ module.exports = {
return testPath;
},
- testPathForConsistencyCheck: '/dist/src/example.test.js',
+ // Normalize to prevent assertion failures on Windows:
+ testPathForConsistencyCheck: path.normalize('/dist/src/example.test.js'),
};