Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error running tests #13

Closed
renehernandez opened this issue Apr 13, 2021 · 9 comments
Closed

Error running tests #13

renehernandez opened this issue Apr 13, 2021 · 9 comments

Comments

@renehernandez
Copy link

Currently, I import the obsidian module in the fileDoc.ts as follows:

import type { App } from "obsidian";

As part of removing the path library from the code, I have switched to use normalizePath function as seen on fileDoc.ts on branch remove-path-api as follows:

import { FileSystemAdapter, normalizePath } from "obsidian";

With this changes, which eliminates the usage of type from the import statement, my tests no longer work as seen in this Action run.

Run npm run test

> obsidian-readwise@0.0.2 test /home/runner/work/obsidian-readwise/obsidian-readwise
> mocha -r ts-node/register tests/*.ts


Error: Cannot find module 'obsidian'
Require stack:
- /home/runner/work/obsidian-readwise/obsidian-readwise/src/fileDoc.ts
- /home/runner/work/obsidian-readwise/obsidian-readwise/tests/fileDoc.ts
- /home/runner/work/obsidian-readwise/obsidian-readwise/node_modules/mocha/lib/esm-utils.js
- /home/runner/work/obsidian-readwise/obsidian-readwise/node_modules/mocha/lib/mocha.js
- /home/runner/work/obsidian-readwise/obsidian-readwise/node_modules/mocha/lib/cli/one-and-dones.js
- /home/runner/work/obsidian-readwise/obsidian-readwise/node_modules/mocha/lib/cli/options.js
- /home/runner/work/obsidian-readwise/obsidian-readwise/node_modules/mocha/bin/mocha
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:880:15)
    at Function.Module._load (internal/modules/cjs/loader.js:725:27)
    at Module.require (internal/modules/cjs/loader.js:952:19)
    at require (internal/modules/cjs/helpers.js:88:18)
    at Object.<anonymous> (/home/runner/work/obsidian-readwise/obsidian-readwise/src/fileDoc.ts:4:1)
    at Module._compile (internal/modules/cjs/loader.js:1063:30)
    at Module.m._compile (/home/runner/work/obsidian-readwise/obsidian-readwise/node_modules/ts-node/src/index.ts:1056:23)
    at Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Object.require.extensions.<computed> [as .ts] (/home/runner/work/obsidian-readwise/obsidian-readwise/node_modules/ts-node/src/index.ts:1059:12)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Module.require (internal/modules/cjs/loader.js:952:19)
    at require (internal/modules/cjs/helpers.js:88:18)
    at Object.<anonymous> (/home/runner/work/obsidian-readwise/obsidian-readwise/tests/fileDoc.ts:3:1)
    at Module._compile (internal/modules/cjs/loader.js:1063:30)
    at Module.m._compile (/home/runner/work/obsidian-readwise/obsidian-readwise/node_modules/ts-node/src/index.ts:1056:23)
    at Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Object.require.extensions.<computed> [as .ts] (/home/runner/work/obsidian-readwise/obsidian-readwise/node_modules/ts-node/src/index.ts:1059:12)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Module.require (internal/modules/cjs/loader.js:952:19)
    at require (internal/modules/cjs/helpers.js:88:18)
    at Object.exports.requireOrImport (/home/runner/work/obsidian-readwise/obsidian-readwise/node_modules/mocha/lib/esm-utils.js:42:12)
    at Object.exports.loadFilesAsync (/home/runner/work/obsidian-readwise/obsidian-readwise/node_modules/mocha/lib/esm-utils.js:55:34)
    at Mocha.loadFilesAsync (/home/runner/work/obsidian-readwise/obsidian-readwise/node_modules/mocha/lib/mocha.js:473:19)
    at singleRun (/home/runner/work/obsidian-readwise/obsidian-readwise/node_modules/mocha/lib/cli/run-helpers.js:125:15)
    at exports.runMocha (/home/runner/work/obsidian-readwise/obsidian-readwise/node_modules/mocha/lib/cli/run-helpers.js:190:10)
    at Object.exports.handler (/home/runner/work/obsidian-readwise/obsidian-readwise/node_modules/mocha/lib/cli/run.js:362:11)
    at /home/runner/work/obsidian-readwise/obsidian-readwise/node_modules/yargs/build/index.cjs:443:71
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! obsidian-readwise@0.0.2 test: `mocha -r ts-node/register tests/*.ts`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the obsidian-readwise@0.0.2 test script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/runner/.npm/_logs/2021-04-13T12_38_37_318Z-debug.log
Error: Process completed with exit code 1.
@SilentVoid13
Copy link

SilentVoid13 commented Apr 13, 2021

@renehernandez This is a known problem and limitation of the existing obsidian API.

Because the "obisidian" npm package only contains the declaration file obsidian.d.ts, we don't have access to the "real" code when running outside the obsidian app. This means that you won't be able to use any function / class from obsidian in your tests.

To run unit tests, you would have to run the test code in the obsidian app, like a plugin.
This is not an ideal solution, because this defeats the purpose of testing frameworks like mocha, jest, ....
I think this is what the obsidian-outliner plugin (https://github.com/vslinko/obsidian-outliner) from @vslinko is doing if you want an example.

I don't really like this solution, and I think we should find a solution to be able to use testing frameworks from outside the obsidian app.
I'm curious of what @lishid thinks about this.

@lishid
Copy link
Collaborator

lishid commented Apr 13, 2021

If your code is using functions and classes from obsidian's package, then running it from within Obsidian as a plugin is currently the only way right now. You could tweak the codebase to isolate code that's purely functional and does not depend on Obsidian's API for your tests, or attempt to mock out the obsidian package.

It's definitely not ideal, but designing a system that can accurately emulate the app's environment is fairly challenging. Perhaps we'll spend some time thinking about this later once the app is more mature and the API is more stable.

@renehernandez
Copy link
Author

I was able to abstract the usage of the filesystem capabilities from obsidian through an internal interface and depend on said interface instead of FileSystemAdapter directly. That way I can introduce a fake object during test to verify the logic I wanted in the FileDoc object.

PR: renehernandez/obsidian-readwise#26

@lishid @SilentVoid13 Thanks for the feedback and suggestions

@lishid
Copy link
Collaborator

lishid commented Jul 15, 2021

There's a couple of ways to test plugins at this point. We might consider providing an official framework for testing in the future.

Here are some samples of tests:

Frameworks:

@lishid lishid closed this as completed Jul 15, 2021
@timhor
Copy link

timhor commented Jan 3, 2022

If anyone just needs to test editor-related functionality, I've had success substituting CodeMirror as the editor on which my tests run (that's what Obsidian uses under the hood anyway).

For example:

@claremacrae
Copy link
Contributor

That URL gives a 404 now

It's now:

@claremacrae
Copy link
Contributor

For anyone else finding this issue when searching for help testing Obsidian plugin code, there's now a set of notes on the Obsidian Hub:

for Plugin Developers to Automate Tests

Amongst other things, the above links to ...

How to test plugin code that uses Obsidian APIs

.... which cribs heavily from this issue, and will - I hope - be updated over time as the community learns more about automated testing for plugin code.

@RafaelGB
Copy link

RafaelGB commented May 5, 2022

I found a way to mock interfaces with the library 'jest-mock-extended'

here's an example:

import { MockProxy, mock, mockDeep, DeepMockProxy } from 'jest-mock-extended';
import { labTest1 } from 'mock/labTest';
import { App, TFile } from 'obsidian';
test('test', () => {
    const tfileArrayMock: MockProxy<TFile[]> = mock<TFile[]>();
    tfileArrayMock
    // @ts-ignore
    const mockObj: DeepMockProxy<App> = mockDeep<App>();
    global.app = mockObj;
    mockObj.vault.getFiles.mockReturnValue(fakeGetFilesResponse);
    expect(labTest1()).toEqual(fakeGetFilesResponse);
});

const fakeGetFilesResponse: TFile[] = [
    {
        "name": "file1",
        "path": "path1",
        "parent": {
            "name": "folder1",
            "children": [
                {
                    "name": "file2",
                    "path": "path2",
                    "vault": null,
                    "parent": null,
                },
            ],
            "isRoot": () => true,
            "vault": null,
            "path": "path1",
            "parent": null
        },
        "basename": "file1",
        "vault": null,
        "extension": "",
        "stat": null
    },
    {
        "name": "file2",
        "path": "path2",
        "parent": {
            "name": "folder1",
            "children": [
                {
                    "name": "file2",
                    "path": "path2",
                    "vault": null,
                    "parent": null,
                },
            ],
            "isRoot": () => true,
            "vault": null,
            "path": "path1",
            "parent": null
        },
        "basename": "file2",
        "vault": null,
        "extension": "",
        "stat": null
    },
];

Where labTest1() is

export function labTest1() {
    return app.vault.getFiles()
}

The current problem of this is a limitation of Typescript with recursive typing. You need to add // @ts-ignore behind mockDeep<App>(); and this rule on your .eslintrc.js

rules: {
        "@typescript-eslint/ban-ts-comment": [
          "error",
          {
            "ts-ignore": false
          }
        ],
    },

It works!

@leonhma
Copy link

leonhma commented Oct 30, 2022

How about we just include a simple mock with the obsidian API package that mocks the logic and return values behind these functions? Nothing graphical. Shouldn't be too hard and would at least restore some functionality.

edonyzpc added a commit to edonyzpc/personal-assistant that referenced this issue Apr 26, 2023
According to obsidianmd/obsidian-api#13,
apply testing framework will be failed. So jest just can do some UT.
And the e2e testing should choose another way, maybe obsidian official
can supply this.

Signed-off-by: edonyzpc <edonyzpc@yahoo.com>
edonyzpc added a commit to edonyzpc/personal-assistant that referenced this issue Apr 27, 2023
According to obsidianmd/obsidian-api#13,
apply testing framework will be failed. So jest just can do some UT.
And the e2e testing should choose another way, maybe obsidian official
can supply this.

Signed-off-by: edonyzpc <edonyzpc@yahoo.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants