mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
196 lines
5.5 KiB
TypeScript
196 lines
5.5 KiB
TypeScript
import * as workflowHelpers from '@/composables/useWorkflowHelpers';
|
|
import { SETTINGS_STORE_DEFAULT_STATE } from '@/__tests__/utils';
|
|
import { STORES } from '@/constants';
|
|
import { createTestingPinia } from '@pinia/testing';
|
|
|
|
import SqlEditor from '@/components/SqlEditor/SqlEditor.vue';
|
|
import { renderComponent } from '@/__tests__/render';
|
|
import { waitFor } from '@testing-library/vue';
|
|
import { userEvent } from '@testing-library/user-event';
|
|
import { setActivePinia } from 'pinia';
|
|
import { useRouter } from 'vue-router';
|
|
import { useWorkflowsStore } from '@/stores/workflows.store';
|
|
import type { INodeUi } from '@/Interface';
|
|
|
|
const EXPRESSION_OUTPUT_TEST_ID = 'inline-expression-editor-output';
|
|
|
|
const DEFAULT_SETUP = {
|
|
props: {
|
|
dialect: 'PostgreSQL',
|
|
isReadOnly: false,
|
|
},
|
|
};
|
|
|
|
async function focusEditor(container: Element) {
|
|
await waitFor(() => expect(container.querySelector('.cm-line')).toBeInTheDocument());
|
|
await userEvent.click(container.querySelector('.cm-line') as Element);
|
|
}
|
|
|
|
const nodes = [
|
|
{
|
|
id: '1',
|
|
typeVersion: 1,
|
|
name: 'Test Node',
|
|
position: [0, 0],
|
|
type: 'test',
|
|
parameters: {},
|
|
},
|
|
] as INodeUi[];
|
|
|
|
const mockResolveExpression = () => {
|
|
const mock = vi.fn();
|
|
vi.spyOn(workflowHelpers, 'useWorkflowHelpers').mockReturnValueOnce({
|
|
...workflowHelpers.useWorkflowHelpers({ router: useRouter() }),
|
|
resolveExpression: mock,
|
|
});
|
|
|
|
return mock;
|
|
};
|
|
|
|
describe('SqlEditor.vue', () => {
|
|
beforeEach(() => {
|
|
const pinia = createTestingPinia({
|
|
initialState: {
|
|
[STORES.SETTINGS]: {
|
|
settings: SETTINGS_STORE_DEFAULT_STATE.settings,
|
|
},
|
|
[STORES.NDV]: {
|
|
activeNodeName: 'Test Node',
|
|
},
|
|
[STORES.WORKFLOWS]: {
|
|
workflow: {
|
|
nodes,
|
|
connections: {},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
setActivePinia(pinia);
|
|
|
|
const workflowsStore = useWorkflowsStore();
|
|
vi.mocked(workflowsStore).getNodeByName.mockReturnValue(nodes[0]);
|
|
});
|
|
|
|
afterAll(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it('renders basic query', async () => {
|
|
const { getByTestId, container } = renderComponent(SqlEditor, {
|
|
...DEFAULT_SETUP,
|
|
props: {
|
|
...DEFAULT_SETUP.props,
|
|
modelValue: 'SELECT * FROM users',
|
|
},
|
|
});
|
|
|
|
await focusEditor(container);
|
|
await waitFor(() =>
|
|
expect(getByTestId(EXPRESSION_OUTPUT_TEST_ID)).toHaveTextContent('SELECT * FROM users'),
|
|
);
|
|
});
|
|
|
|
it('renders basic query with expression', async () => {
|
|
mockResolveExpression().mockReturnValueOnce('users');
|
|
const { getByTestId, container } = renderComponent(SqlEditor, {
|
|
...DEFAULT_SETUP,
|
|
props: {
|
|
...DEFAULT_SETUP.props,
|
|
modelValue: 'SELECT * FROM {{ $json.table }}',
|
|
},
|
|
});
|
|
|
|
await focusEditor(container);
|
|
await waitFor(() =>
|
|
expect(getByTestId(EXPRESSION_OUTPUT_TEST_ID)).toHaveTextContent('SELECT * FROM users'),
|
|
);
|
|
});
|
|
|
|
it('renders resolved expressions with dot between resolvables', async () => {
|
|
mockResolveExpression().mockReturnValueOnce('public.users');
|
|
const { getByTestId, container } = renderComponent(SqlEditor, {
|
|
...DEFAULT_SETUP,
|
|
props: {
|
|
...DEFAULT_SETUP.props,
|
|
modelValue: 'SELECT * FROM {{ $json.schema }}.{{ $json.table }}',
|
|
},
|
|
});
|
|
|
|
await focusEditor(container);
|
|
await waitFor(() =>
|
|
expect(getByTestId(EXPRESSION_OUTPUT_TEST_ID)).toHaveTextContent(
|
|
'SELECT * FROM public.users',
|
|
),
|
|
);
|
|
});
|
|
|
|
it('renders resolved expressions which resolve to 0', async () => {
|
|
mockResolveExpression()
|
|
.mockReturnValueOnce('public')
|
|
.mockReturnValueOnce('users')
|
|
.mockReturnValueOnce('id')
|
|
.mockReturnValueOnce(0);
|
|
const { getByTestId, container } = renderComponent(SqlEditor, {
|
|
...DEFAULT_SETUP,
|
|
props: {
|
|
...DEFAULT_SETUP.props,
|
|
modelValue:
|
|
'SELECT * FROM {{ $json.schema }}.{{ $json.table }} WHERE {{ $json.id }} > {{ $json.limit - 10 }}',
|
|
},
|
|
});
|
|
|
|
await focusEditor(container);
|
|
await waitFor(() =>
|
|
expect(getByTestId(EXPRESSION_OUTPUT_TEST_ID)).toHaveTextContent(
|
|
'SELECT * FROM public.users WHERE id > 0',
|
|
),
|
|
);
|
|
});
|
|
|
|
it('keeps query formatting in rendered output', async () => {
|
|
mockResolveExpression()
|
|
.mockReturnValueOnce('public')
|
|
.mockReturnValueOnce('users')
|
|
.mockReturnValueOnce(0)
|
|
.mockReturnValueOnce(false);
|
|
const { getByTestId, container } = renderComponent(SqlEditor, {
|
|
...DEFAULT_SETUP,
|
|
props: {
|
|
...DEFAULT_SETUP.props,
|
|
modelValue:
|
|
'SELECT * FROM {{ $json.schema }}.{{ $json.table }}\n WHERE id > {{ $json.limit - 10 }}\n AND active = {{ $json.active }};',
|
|
},
|
|
});
|
|
|
|
await focusEditor(container);
|
|
await waitFor(() =>
|
|
expect(getByTestId(EXPRESSION_OUTPUT_TEST_ID)).toHaveTextContent(
|
|
'SELECT * FROM public.users WHERE id > 0 AND active = false;',
|
|
),
|
|
);
|
|
// Output should have the same number of lines as the input
|
|
expect(getByTestId('sql-editor-container').getElementsByClassName('cm-line').length).toEqual(
|
|
getByTestId(EXPRESSION_OUTPUT_TEST_ID).getElementsByClassName('cm-line').length,
|
|
);
|
|
});
|
|
|
|
it('should keep rendered output visible when clicking', async () => {
|
|
const { getByTestId, queryByTestId, container, baseElement } = renderComponent(SqlEditor, {
|
|
...DEFAULT_SETUP,
|
|
props: {
|
|
...DEFAULT_SETUP.props,
|
|
modelValue: 'SELECT * FROM users',
|
|
},
|
|
});
|
|
|
|
// Does not hide output when clicking inside the output
|
|
await focusEditor(container);
|
|
await userEvent.click(getByTestId(EXPRESSION_OUTPUT_TEST_ID));
|
|
await waitFor(() => expect(queryByTestId(EXPRESSION_OUTPUT_TEST_ID)).toBeInTheDocument());
|
|
|
|
// Does hide output when clicking outside the container
|
|
await userEvent.click(baseElement);
|
|
await waitFor(() => expect(queryByTestId(EXPRESSION_OUTPUT_TEST_ID)).not.toBeInTheDocument());
|
|
});
|
|
});
|