first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled

This commit is contained in:
2026-03-17 16:22:57 +03:30
commit 3d5eaf9445
15349 changed files with 2847338 additions and 0 deletions
@@ -0,0 +1,200 @@
import type { IExecuteFunctions } from 'n8n-workflow';
import { execute } from '../../../../v2/actions/spreadsheet/create.operation';
import { apiRequest } from '../../../../v2/transport';
jest.mock('../../../../v2/transport', () => ({
apiRequest: {
call: jest.fn(),
},
}));
describe('Spreadsheet Create Operation', () => {
let mockExecuteFunctions: IExecuteFunctions;
beforeEach(() => {
mockExecuteFunctions = {
getInputData: jest.fn().mockReturnValue([{}]),
getNodeParameter: jest.fn(),
helpers: {
constructExecutionMetaData: jest.fn().mockImplementation((data) => data),
},
} as unknown as IExecuteFunctions;
jest.clearAllMocks();
});
describe('execute', () => {
it('should create a basic spreadsheet with title only', async () => {
const mockTitle = 'Test Spreadsheet';
const mockResponse = { spreadsheetId: '1234', title: mockTitle };
mockExecuteFunctions.getNodeParameter = jest
.fn()
.mockReturnValueOnce(mockTitle)
.mockReturnValueOnce({})
.mockReturnValueOnce({});
(apiRequest.call as jest.Mock).mockResolvedValueOnce(mockResponse);
const result = await execute.call(mockExecuteFunctions);
expect(apiRequest.call).toHaveBeenCalledWith(
mockExecuteFunctions,
'POST',
'/v4/spreadsheets',
{
properties: {
title: mockTitle,
autoRecalc: undefined,
locale: undefined,
},
sheets: [],
},
);
expect(result).toHaveLength(1);
expect(result[0]).toEqual({ json: mockResponse });
});
it('should create spreadsheet with multiple sheets', async () => {
const mockSheets = {
sheetValues: [
{ title: 'Sheet1', hidden: false },
{ title: 'Sheet2', hidden: true },
],
};
mockExecuteFunctions.getNodeParameter = jest
.fn()
.mockReturnValueOnce('Test Spreadsheet')
.mockReturnValueOnce(mockSheets)
.mockReturnValueOnce({});
const mockResponse = { spreadsheetId: '1234' };
(apiRequest.call as jest.Mock).mockResolvedValueOnce(mockResponse);
await execute.call(mockExecuteFunctions);
expect(apiRequest.call).toHaveBeenCalledWith(
mockExecuteFunctions,
'POST',
'/v4/spreadsheets',
{
properties: {
title: 'Test Spreadsheet',
autoRecalc: undefined,
locale: undefined,
},
sheets: [
{ properties: { title: 'Sheet1', hidden: false } },
{ properties: { title: 'Sheet2', hidden: true } },
],
},
);
});
it('should handle all options when creating spreadsheet', async () => {
const mockOptions = {
locale: 'en_US',
autoRecalc: 'ON_CHANGE',
};
mockExecuteFunctions.getNodeParameter = jest
.fn()
.mockReturnValueOnce('Test Spreadsheet')
.mockReturnValueOnce({})
.mockReturnValueOnce(mockOptions);
const mockResponse = { spreadsheetId: '1234' };
(apiRequest.call as jest.Mock).mockResolvedValueOnce(mockResponse);
await execute.call(mockExecuteFunctions);
expect(apiRequest.call).toHaveBeenCalledWith(
mockExecuteFunctions,
'POST',
'/v4/spreadsheets',
{
properties: {
title: 'Test Spreadsheet',
autoRecalc: 'ON_CHANGE',
locale: 'en_US',
},
sheets: [],
},
);
});
it('should handle multiple input items', async () => {
mockExecuteFunctions.getInputData = jest.fn().mockReturnValue([{}, {}]);
const mockResponse1 = { spreadsheetId: '1234' };
const mockResponse2 = { spreadsheetId: '5678' };
mockExecuteFunctions.getNodeParameter = jest
.fn()
.mockReturnValueOnce('Spreadsheet 1')
.mockReturnValueOnce({})
.mockReturnValueOnce({})
.mockReturnValueOnce('Spreadsheet 2')
.mockReturnValueOnce({})
.mockReturnValueOnce({});
(apiRequest.call as jest.Mock)
.mockResolvedValueOnce(mockResponse1)
.mockResolvedValueOnce(mockResponse2);
const result = await execute.call(mockExecuteFunctions);
expect(result).toHaveLength(2);
expect(apiRequest.call).toHaveBeenCalledTimes(2);
expect(result[0]).toEqual({ json: mockResponse1 });
expect(result[1]).toEqual({ json: mockResponse2 });
});
it('should handle empty sheet properties', async () => {
mockExecuteFunctions.getNodeParameter = jest
.fn()
.mockReturnValueOnce('Test Spreadsheet')
.mockReturnValueOnce({ sheetValues: [] })
.mockReturnValueOnce({});
const mockResponse = { spreadsheetId: '1234' };
(apiRequest.call as jest.Mock).mockResolvedValueOnce(mockResponse);
await execute.call(mockExecuteFunctions);
expect(apiRequest.call).toHaveBeenCalledWith(
expect.anything(),
'POST',
'/v4/spreadsheets',
expect.objectContaining({
sheets: [],
}),
);
});
it('should preserve undefined values for optional properties', async () => {
mockExecuteFunctions.getNodeParameter = jest
.fn()
.mockReturnValueOnce('Test Spreadsheet')
.mockReturnValueOnce({})
.mockReturnValueOnce({});
const mockResponse = { spreadsheetId: '1234' };
(apiRequest.call as jest.Mock).mockResolvedValueOnce(mockResponse);
await execute.call(mockExecuteFunctions);
expect(apiRequest.call).toHaveBeenCalledWith(expect.anything(), 'POST', '/v4/spreadsheets', {
properties: {
title: 'Test Spreadsheet',
autoRecalc: undefined,
locale: undefined,
},
sheets: [],
});
});
});
});
@@ -0,0 +1,119 @@
import type { IExecuteFunctions } from 'n8n-workflow';
import { execute } from '../../../../v2/actions/spreadsheet/delete.operation';
import { apiRequest } from '../../../../v2/transport';
jest.mock('../../../../v2/transport', () => ({
apiRequest: {
call: jest.fn(),
},
}));
describe('GoogleSheetsDeleteSpreadsheet', () => {
let mockExecuteFunction: IExecuteFunctions;
beforeEach(() => {
mockExecuteFunction = {
getInputData: jest.fn().mockReturnValue([{}]),
getNodeParameter: jest.fn(),
helpers: {
constructExecutionMetaData: jest.fn().mockImplementation((data) => [data]),
},
} as unknown as IExecuteFunctions;
jest.clearAllMocks();
});
it('should successfully delete a spreadsheet', async () => {
const documentId = '1234567890';
const expectedUrl = `https://www.googleapis.com/drive/v3/files/${documentId}`;
mockExecuteFunction.getNodeParameter = jest.fn().mockReturnValue(documentId);
(apiRequest.call as jest.Mock).mockResolvedValue({});
const result = await execute.call(mockExecuteFunction);
expect(apiRequest.call).toHaveBeenCalledWith(
mockExecuteFunction,
'DELETE',
'',
{},
{},
expectedUrl,
);
expect(result).toHaveLength(1);
expect(result).toEqual([[{ json: { success: true } }]]);
});
it('should handle multiple input items', async () => {
const documentIds = ['doc1', 'doc2', 'doc3'];
mockExecuteFunction.getInputData = jest.fn().mockReturnValue([{}, {}, {}]);
mockExecuteFunction.getNodeParameter = jest
.fn()
.mockImplementation((_, index) => documentIds[index]);
(apiRequest.call as jest.Mock).mockResolvedValue({});
const result = await execute.call(mockExecuteFunction);
expect(apiRequest.call).toHaveBeenCalledTimes(3);
expect(result).toHaveLength(3);
result.forEach((item) => {
expect(item).toEqual([{ json: { success: true } }]);
});
});
it('should handle API errors gracefully', async () => {
const documentId = '1234567890';
const errorMessage = 'File not found';
mockExecuteFunction.getNodeParameter = jest.fn().mockReturnValue(documentId);
(apiRequest.call as jest.Mock).mockRejectedValue(new Error(errorMessage));
await expect(execute.call(mockExecuteFunction)).rejects.toThrow(Error);
});
it('should validate document ID parameter', async () => {
mockExecuteFunction.getNodeParameter = jest.fn().mockReturnValue(undefined);
await expect(execute.call(mockExecuteFunction)).rejects.toThrow();
});
describe('Resource Locator Modes', () => {
it('should handle list mode correctly', async () => {
const documentId = '1234567890';
mockExecuteFunction.getNodeParameter = jest.fn().mockReturnValue({
mode: 'list',
value: documentId,
});
(apiRequest.call as jest.Mock).mockResolvedValue({});
const result = await execute.call(mockExecuteFunction);
expect(result).toEqual([[{ json: { success: true } }]]);
});
it('should handle URL mode correctly', async () => {
const documentUrl = 'https://docs.google.com/spreadsheets/d/1234567890/edit';
mockExecuteFunction.getNodeParameter = jest.fn().mockReturnValue({
mode: 'url',
value: documentUrl,
});
(apiRequest.call as jest.Mock).mockResolvedValue({});
const result = await execute.call(mockExecuteFunction);
expect(result).toEqual([[{ json: { success: true } }]]);
});
it('should handle ID mode correctly', async () => {
const documentId = '1234567890';
mockExecuteFunction.getNodeParameter = jest.fn().mockReturnValue({
mode: 'id',
value: documentId,
});
(apiRequest.call as jest.Mock).mockResolvedValue({});
const result = await execute.call(mockExecuteFunction);
expect(result).toEqual([[{ json: { success: true } }]]);
});
});
});