test(app): write model tests
This commit is contained in:
73
packages/backend/src/models/__snapshots__/app.test.js.snap
Normal file
73
packages/backend/src/models/__snapshots__/app.test.js.snap
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
|
exports[`App model > list should have list of applications keys 1`] = `
|
||||||
|
[
|
||||||
|
"airtable",
|
||||||
|
"appwrite",
|
||||||
|
"azure-openai",
|
||||||
|
"carbone",
|
||||||
|
"clickup",
|
||||||
|
"code",
|
||||||
|
"cryptography",
|
||||||
|
"datastore",
|
||||||
|
"deepl",
|
||||||
|
"delay",
|
||||||
|
"discord",
|
||||||
|
"disqus",
|
||||||
|
"dropbox",
|
||||||
|
"filter",
|
||||||
|
"flickr",
|
||||||
|
"flowers-software",
|
||||||
|
"formatter",
|
||||||
|
"ghost",
|
||||||
|
"github",
|
||||||
|
"gitlab",
|
||||||
|
"google-calendar",
|
||||||
|
"google-drive",
|
||||||
|
"google-forms",
|
||||||
|
"google-sheets",
|
||||||
|
"google-tasks",
|
||||||
|
"helix",
|
||||||
|
"http-request",
|
||||||
|
"hubspot",
|
||||||
|
"invoice-ninja",
|
||||||
|
"jotform",
|
||||||
|
"mailchimp",
|
||||||
|
"mailerlite",
|
||||||
|
"mattermost",
|
||||||
|
"miro",
|
||||||
|
"notion",
|
||||||
|
"ntfy",
|
||||||
|
"odoo",
|
||||||
|
"openai",
|
||||||
|
"pipedrive",
|
||||||
|
"placetel",
|
||||||
|
"postgresql",
|
||||||
|
"pushover",
|
||||||
|
"reddit",
|
||||||
|
"removebg",
|
||||||
|
"rss",
|
||||||
|
"salesforce",
|
||||||
|
"scheduler",
|
||||||
|
"self-hosted-llm",
|
||||||
|
"signalwire",
|
||||||
|
"slack",
|
||||||
|
"smtp",
|
||||||
|
"spotify",
|
||||||
|
"strava",
|
||||||
|
"stripe",
|
||||||
|
"telegram-bot",
|
||||||
|
"todoist",
|
||||||
|
"trello",
|
||||||
|
"twilio",
|
||||||
|
"twitter",
|
||||||
|
"typeform",
|
||||||
|
"vtiger-crm",
|
||||||
|
"webhook",
|
||||||
|
"wordpress",
|
||||||
|
"xero",
|
||||||
|
"you-need-a-budget",
|
||||||
|
"youtube",
|
||||||
|
"zendesk",
|
||||||
|
]
|
||||||
|
`;
|
420
packages/backend/src/models/app.test.js
Normal file
420
packages/backend/src/models/app.test.js
Normal file
@@ -0,0 +1,420 @@
|
|||||||
|
import { describe, it, expect, vi } from 'vitest';
|
||||||
|
|
||||||
|
import App from './app.js';
|
||||||
|
import * as getAppModule from '../helpers/get-app.js';
|
||||||
|
import * as appInfoConverterModule from '../helpers/app-info-converter.js';
|
||||||
|
|
||||||
|
describe('App model', () => {
|
||||||
|
it('folderPath should return correct path', () => {
|
||||||
|
expect(App.folderPath).toEqual(
|
||||||
|
expect.stringMatching(/\/packages\/backend\/src\/apps$/)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('list should have list of applications keys', () => {
|
||||||
|
expect(App.list).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findAll', () => {
|
||||||
|
it('should return all applications', async () => {
|
||||||
|
const apps = await App.findAll();
|
||||||
|
|
||||||
|
expect(apps.length).toBe(App.list.length);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return matching applications when name argument is given', async () => {
|
||||||
|
const apps = await App.findAll('deepl');
|
||||||
|
|
||||||
|
expect(apps.length).toBe(1);
|
||||||
|
expect(apps[0].key).toBe('deepl');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return matching applications in plain JSON when stripFunc argument is true', async () => {
|
||||||
|
const appFindOneByNameSpy = vi.spyOn(App, 'findOneByName');
|
||||||
|
|
||||||
|
await App.findAll('deepl', true);
|
||||||
|
|
||||||
|
expect(appFindOneByNameSpy).toHaveBeenCalledWith('deepl', true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findOneByName', () => {
|
||||||
|
it('should return app info for given app name', async () => {
|
||||||
|
const getAppSpy = vi
|
||||||
|
.spyOn(getAppModule, 'default')
|
||||||
|
.mockImplementation(() => 'mock-app');
|
||||||
|
|
||||||
|
const appInfoConverterSpy = vi
|
||||||
|
.spyOn(appInfoConverterModule, 'default')
|
||||||
|
.mockImplementation(() => 'app-info');
|
||||||
|
|
||||||
|
const app = await App.findOneByName('DeepL');
|
||||||
|
|
||||||
|
expect(getAppSpy).toHaveBeenCalledWith('deepl', false);
|
||||||
|
expect(appInfoConverterSpy).toHaveBeenCalledWith('mock-app');
|
||||||
|
expect(app).toStrictEqual('app-info');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return app info for given app name in plain JSON when stripFunc argument is true', async () => {
|
||||||
|
const getAppSpy = vi
|
||||||
|
.spyOn(getAppModule, 'default')
|
||||||
|
.mockImplementation(() => 'mock-app');
|
||||||
|
|
||||||
|
const appInfoConverterSpy = vi
|
||||||
|
.spyOn(appInfoConverterModule, 'default')
|
||||||
|
.mockImplementation(() => 'app-info');
|
||||||
|
|
||||||
|
const app = await App.findOneByName('DeepL', true);
|
||||||
|
|
||||||
|
expect(getAppSpy).toHaveBeenCalledWith('deepl', true);
|
||||||
|
expect(appInfoConverterSpy).toHaveBeenCalledWith('mock-app');
|
||||||
|
expect(app).toStrictEqual('app-info');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findOneByKey', () => {
|
||||||
|
it('should return app info for given app key', async () => {
|
||||||
|
const getAppSpy = vi
|
||||||
|
.spyOn(getAppModule, 'default')
|
||||||
|
.mockImplementation(() => 'mock-app');
|
||||||
|
|
||||||
|
const appInfoConverterSpy = vi
|
||||||
|
.spyOn(appInfoConverterModule, 'default')
|
||||||
|
.mockImplementation(() => 'app-info');
|
||||||
|
|
||||||
|
const app = await App.findOneByKey('deepl');
|
||||||
|
|
||||||
|
expect(getAppSpy).toHaveBeenCalledWith('deepl', false);
|
||||||
|
expect(appInfoConverterSpy).toHaveBeenCalledWith('mock-app');
|
||||||
|
expect(app).toStrictEqual('app-info');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return app info for given app key in plain JSON when stripFunc argument is true', async () => {
|
||||||
|
const getAppSpy = vi
|
||||||
|
.spyOn(getAppModule, 'default')
|
||||||
|
.mockImplementation(() => 'mock-app');
|
||||||
|
|
||||||
|
const appInfoConverterSpy = vi
|
||||||
|
.spyOn(appInfoConverterModule, 'default')
|
||||||
|
.mockImplementation(() => 'app-info');
|
||||||
|
|
||||||
|
const app = await App.findOneByKey('deepl', true);
|
||||||
|
|
||||||
|
expect(getAppSpy).toHaveBeenCalledWith('deepl', true);
|
||||||
|
expect(appInfoConverterSpy).toHaveBeenCalledWith('mock-app');
|
||||||
|
expect(app).toStrictEqual('app-info');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findAuthByKey', () => {
|
||||||
|
it('should return app auth for given app key', async () => {
|
||||||
|
const getAppSpy = vi
|
||||||
|
.spyOn(getAppModule, 'default')
|
||||||
|
.mockImplementation(() => ({ auth: 'mock-auth' }));
|
||||||
|
|
||||||
|
const appInfoConverterSpy = vi
|
||||||
|
.spyOn(appInfoConverterModule, 'default')
|
||||||
|
.mockImplementation((input) => input);
|
||||||
|
|
||||||
|
const appAuth = await App.findAuthByKey('deepl');
|
||||||
|
|
||||||
|
expect(getAppSpy).toHaveBeenCalledWith('deepl', false);
|
||||||
|
expect(appInfoConverterSpy).toHaveBeenCalledWith({ auth: 'mock-auth' });
|
||||||
|
expect(appAuth).toStrictEqual('mock-auth');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return app auth for given app key in plain JSON when stripFunc argument is true', async () => {
|
||||||
|
const getAppSpy = vi
|
||||||
|
.spyOn(getAppModule, 'default')
|
||||||
|
.mockImplementation(() => ({ auth: 'mock-auth' }));
|
||||||
|
|
||||||
|
const appInfoConverterSpy = vi
|
||||||
|
.spyOn(appInfoConverterModule, 'default')
|
||||||
|
.mockImplementation((input) => input);
|
||||||
|
|
||||||
|
const appAuth = await App.findAuthByKey('deepl', true);
|
||||||
|
|
||||||
|
expect(getAppSpy).toHaveBeenCalledWith('deepl', true);
|
||||||
|
expect(appInfoConverterSpy).toHaveBeenCalledWith({ auth: 'mock-auth' });
|
||||||
|
expect(appAuth).toStrictEqual('mock-auth');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findTriggersByKey', () => {
|
||||||
|
it('should return app triggers for given app key', async () => {
|
||||||
|
const getAppSpy = vi
|
||||||
|
.spyOn(getAppModule, 'default')
|
||||||
|
.mockImplementation(() => ({ triggers: 'mock-triggers' }));
|
||||||
|
|
||||||
|
const appInfoConverterSpy = vi
|
||||||
|
.spyOn(appInfoConverterModule, 'default')
|
||||||
|
.mockImplementation((input) => input);
|
||||||
|
|
||||||
|
const appTriggers = await App.findTriggersByKey('deepl');
|
||||||
|
|
||||||
|
expect(getAppSpy).toHaveBeenCalledWith('deepl', false);
|
||||||
|
expect(appInfoConverterSpy).toHaveBeenCalledWith({
|
||||||
|
triggers: 'mock-triggers',
|
||||||
|
});
|
||||||
|
expect(appTriggers).toStrictEqual('mock-triggers');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return app triggers for given app key in plain JSON when stripFunc argument is true', async () => {
|
||||||
|
const getAppSpy = vi
|
||||||
|
.spyOn(getAppModule, 'default')
|
||||||
|
.mockImplementation(() => ({ triggers: 'mock-triggers' }));
|
||||||
|
|
||||||
|
const appInfoConverterSpy = vi
|
||||||
|
.spyOn(appInfoConverterModule, 'default')
|
||||||
|
.mockImplementation((input) => input);
|
||||||
|
|
||||||
|
const appTriggers = await App.findTriggersByKey('deepl', true);
|
||||||
|
|
||||||
|
expect(getAppSpy).toHaveBeenCalledWith('deepl', true);
|
||||||
|
expect(appInfoConverterSpy).toHaveBeenCalledWith({
|
||||||
|
triggers: 'mock-triggers',
|
||||||
|
});
|
||||||
|
expect(appTriggers).toStrictEqual('mock-triggers');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findTriggerSubsteps', () => {
|
||||||
|
it('should return app trigger substeps for given app key', async () => {
|
||||||
|
const getAppSpy = vi
|
||||||
|
.spyOn(getAppModule, 'default')
|
||||||
|
.mockImplementation(() => ({
|
||||||
|
triggers: [{ key: 'mock-trigger', substeps: 'mock-substeps' }],
|
||||||
|
}));
|
||||||
|
|
||||||
|
const appInfoConverterSpy = vi
|
||||||
|
.spyOn(appInfoConverterModule, 'default')
|
||||||
|
.mockImplementation((input) => input);
|
||||||
|
|
||||||
|
const appTriggerSubsteps = await App.findTriggerSubsteps(
|
||||||
|
'deepl',
|
||||||
|
'mock-trigger'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(getAppSpy).toHaveBeenCalledWith('deepl', false);
|
||||||
|
expect(appInfoConverterSpy).toHaveBeenCalledWith({
|
||||||
|
triggers: [{ key: 'mock-trigger', substeps: 'mock-substeps' }],
|
||||||
|
});
|
||||||
|
expect(appTriggerSubsteps).toStrictEqual('mock-substeps');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return app trigger substeps for given app key in plain JSON when stripFunc argument is true', async () => {
|
||||||
|
const getAppSpy = vi
|
||||||
|
.spyOn(getAppModule, 'default')
|
||||||
|
.mockImplementation(() => ({
|
||||||
|
triggers: [{ key: 'mock-trigger', substeps: 'mock-substeps' }],
|
||||||
|
}));
|
||||||
|
|
||||||
|
const appInfoConverterSpy = vi
|
||||||
|
.spyOn(appInfoConverterModule, 'default')
|
||||||
|
.mockImplementation((input) => input);
|
||||||
|
|
||||||
|
const appTriggerSubsteps = await App.findTriggerSubsteps(
|
||||||
|
'deepl',
|
||||||
|
'mock-trigger',
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(getAppSpy).toHaveBeenCalledWith('deepl', true);
|
||||||
|
expect(appInfoConverterSpy).toHaveBeenCalledWith({
|
||||||
|
triggers: [{ key: 'mock-trigger', substeps: 'mock-substeps' }],
|
||||||
|
});
|
||||||
|
expect(appTriggerSubsteps).toStrictEqual('mock-substeps');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findActionsByKey', () => {
|
||||||
|
it('should return app actions for given app key', async () => {
|
||||||
|
const getAppSpy = vi
|
||||||
|
.spyOn(getAppModule, 'default')
|
||||||
|
.mockImplementation(() => ({ actions: 'mock-actions' }));
|
||||||
|
|
||||||
|
const appInfoConverterSpy = vi
|
||||||
|
.spyOn(appInfoConverterModule, 'default')
|
||||||
|
.mockImplementation((input) => input);
|
||||||
|
|
||||||
|
const appActions = await App.findActionsByKey('deepl');
|
||||||
|
|
||||||
|
expect(getAppSpy).toHaveBeenCalledWith('deepl', false);
|
||||||
|
expect(appInfoConverterSpy).toHaveBeenCalledWith({
|
||||||
|
actions: 'mock-actions',
|
||||||
|
});
|
||||||
|
expect(appActions).toStrictEqual('mock-actions');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return app actions for given app key in plain JSON when stripFunc argument is true', async () => {
|
||||||
|
const getAppSpy = vi
|
||||||
|
.spyOn(getAppModule, 'default')
|
||||||
|
.mockImplementation(() => ({ actions: 'mock-actions' }));
|
||||||
|
|
||||||
|
const appInfoConverterSpy = vi
|
||||||
|
.spyOn(appInfoConverterModule, 'default')
|
||||||
|
.mockImplementation((input) => input);
|
||||||
|
|
||||||
|
const appActions = await App.findActionsByKey('deepl', true);
|
||||||
|
|
||||||
|
expect(getAppSpy).toHaveBeenCalledWith('deepl', true);
|
||||||
|
expect(appInfoConverterSpy).toHaveBeenCalledWith({
|
||||||
|
actions: 'mock-actions',
|
||||||
|
});
|
||||||
|
expect(appActions).toStrictEqual('mock-actions');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findActionSubsteps', () => {
|
||||||
|
it('should return app action substeps for given app key', async () => {
|
||||||
|
const getAppSpy = vi
|
||||||
|
.spyOn(getAppModule, 'default')
|
||||||
|
.mockImplementation(() => ({
|
||||||
|
actions: [{ key: 'mock-action', substeps: 'mock-substeps' }],
|
||||||
|
}));
|
||||||
|
|
||||||
|
const appInfoConverterSpy = vi
|
||||||
|
.spyOn(appInfoConverterModule, 'default')
|
||||||
|
.mockImplementation((input) => input);
|
||||||
|
|
||||||
|
const appActionSubsteps = await App.findActionSubsteps(
|
||||||
|
'deepl',
|
||||||
|
'mock-action'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(getAppSpy).toHaveBeenCalledWith('deepl', false);
|
||||||
|
expect(appInfoConverterSpy).toHaveBeenCalledWith({
|
||||||
|
actions: [{ key: 'mock-action', substeps: 'mock-substeps' }],
|
||||||
|
});
|
||||||
|
expect(appActionSubsteps).toStrictEqual('mock-substeps');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return app action substeps for given app key in plain JSON when stripFunc argument is true', async () => {
|
||||||
|
const getAppSpy = vi
|
||||||
|
.spyOn(getAppModule, 'default')
|
||||||
|
.mockImplementation(() => ({
|
||||||
|
actions: [{ key: 'mock-action', substeps: 'mock-substeps' }],
|
||||||
|
}));
|
||||||
|
|
||||||
|
const appInfoConverterSpy = vi
|
||||||
|
.spyOn(appInfoConverterModule, 'default')
|
||||||
|
.mockImplementation((input) => input);
|
||||||
|
|
||||||
|
const appActionSubsteps = await App.findActionSubsteps(
|
||||||
|
'deepl',
|
||||||
|
'mock-action',
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(getAppSpy).toHaveBeenCalledWith('deepl', true);
|
||||||
|
expect(appInfoConverterSpy).toHaveBeenCalledWith({
|
||||||
|
actions: [{ key: 'mock-action', substeps: 'mock-substeps' }],
|
||||||
|
});
|
||||||
|
expect(appActionSubsteps).toStrictEqual('mock-substeps');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('checkAppAndAction', () => {
|
||||||
|
it('should return undefined when app and action exist', async () => {
|
||||||
|
const findOneByKeySpy = vi
|
||||||
|
.spyOn(App, 'findOneByKey')
|
||||||
|
.mockImplementation(() => ({
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
key: 'translate-text',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}));
|
||||||
|
|
||||||
|
const appAndActionExist = await App.checkAppAndAction(
|
||||||
|
'deepl',
|
||||||
|
'translate-text'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(findOneByKeySpy).toHaveBeenCalledWith('deepl');
|
||||||
|
expect(appAndActionExist).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return undefined when app exists without action argument provided', async () => {
|
||||||
|
const actionFindSpy = vi.fn();
|
||||||
|
const findOneByKeySpy = vi
|
||||||
|
.spyOn(App, 'findOneByKey')
|
||||||
|
.mockImplementation(() => ({
|
||||||
|
actions: {
|
||||||
|
find: actionFindSpy,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const appAndActionExist = await App.checkAppAndAction('deepl');
|
||||||
|
|
||||||
|
expect(findOneByKeySpy).toHaveBeenCalledWith('deepl');
|
||||||
|
expect(actionFindSpy).not.toHaveBeenCalled();
|
||||||
|
expect(appAndActionExist).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error when app exists, but action does not', async () => {
|
||||||
|
const findOneByKeySpy = vi
|
||||||
|
.spyOn(App, 'findOneByKey')
|
||||||
|
.mockImplementation(() => ({ name: 'deepl' }));
|
||||||
|
|
||||||
|
await expect(() =>
|
||||||
|
App.checkAppAndAction('deepl', 'non-existing-action')
|
||||||
|
).rejects.toThrowError(
|
||||||
|
'deepl does not have an action with the "non-existing-action" key!'
|
||||||
|
);
|
||||||
|
expect(findOneByKeySpy).toHaveBeenCalledWith('deepl');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('checkAppAndTrigger', () => {
|
||||||
|
it('should return undefined when app and trigger exist', async () => {
|
||||||
|
const findOneByKeySpy = vi
|
||||||
|
.spyOn(App, 'findOneByKey')
|
||||||
|
.mockImplementation(() => ({
|
||||||
|
triggers: [
|
||||||
|
{
|
||||||
|
key: 'catch-raw-webhook',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}));
|
||||||
|
|
||||||
|
const appAndTriggerExist = await App.checkAppAndTrigger(
|
||||||
|
'webhook',
|
||||||
|
'catch-raw-webhook'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(findOneByKeySpy).toHaveBeenCalledWith('webhook');
|
||||||
|
expect(appAndTriggerExist).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return undefined when app exists without trigger argument provided', async () => {
|
||||||
|
const triggerFindSpy = vi.fn();
|
||||||
|
const findOneByKeySpy = vi
|
||||||
|
.spyOn(App, 'findOneByKey')
|
||||||
|
.mockImplementation(() => ({
|
||||||
|
actions: {
|
||||||
|
find: triggerFindSpy,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const appAndTriggerExist = await App.checkAppAndTrigger('webhook');
|
||||||
|
|
||||||
|
expect(findOneByKeySpy).toHaveBeenCalledWith('webhook');
|
||||||
|
expect(triggerFindSpy).not.toHaveBeenCalled();
|
||||||
|
expect(appAndTriggerExist).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error when app exists, but trigger does not', async () => {
|
||||||
|
const findOneByKeySpy = vi
|
||||||
|
.spyOn(App, 'findOneByKey')
|
||||||
|
.mockImplementation(() => ({ name: 'webhook' }));
|
||||||
|
|
||||||
|
await expect(() =>
|
||||||
|
App.checkAppAndTrigger('webhook', 'non-existing-trigger')
|
||||||
|
).rejects.toThrowError(
|
||||||
|
'webhook does not have a trigger with the "non-existing-trigger" key!'
|
||||||
|
);
|
||||||
|
expect(findOneByKeySpy).toHaveBeenCalledWith('webhook');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Reference in New Issue
Block a user