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,791 @@
import type { ILoadOptionsFunctions, IExecuteFunctions } from 'n8n-workflow';
import { NodeOperationError } from 'n8n-workflow';
import nock from 'nock';
import { returnData } from '../../../E2eTest/mock';
import { googleApiRequest, googleApiRequestAllItems } from '../GenericFunctions';
import { GSuiteAdmin } from '../GSuiteAdmin.node';
jest.mock('../GenericFunctions', () => ({
getGoogleAuth: jest.fn().mockImplementation(() => ({
oauth2Client: {
setCredentials: jest.fn(),
getAccessToken: jest.fn().mockResolvedValue('mock-access-token'),
},
})),
googleApiRequest: jest.fn(),
googleApiRequestAllItems: jest.fn(),
}));
const node = new GSuiteAdmin();
const mockThis = {
getNode: () => ({
name: 'Google Workspace Admin',
parameters: {},
}),
helpers: {
httpRequestWithAuthentication: jest.fn(),
returnJsonArray: (data: any) => data,
constructExecutionMetaData: (data: any) => data,
},
continueOnFail: () => false,
getNodeParameter: jest.fn((name: string) => {
if (name === 'limit') return 50;
return undefined;
}),
} as unknown as ILoadOptionsFunctions;
describe('GSuiteAdmin Node - loadOptions', () => {
beforeEach(() => {
jest.clearAllMocks();
nock.cleanAll();
nock.disableNetConnect();
});
describe('getDomains', () => {
it('should return a list of domains', async () => {
(googleApiRequestAllItems as jest.Mock).mockResolvedValue([
{ domainName: 'example.com' },
{ domainName: 'test.com' },
]);
const result = await node.methods.loadOptions.getDomains.call(mockThis);
expect(result).toEqual([
{ name: 'example.com', value: 'example.com' },
{ name: 'test.com', value: 'test.com' },
]);
});
});
describe('getSchemas', () => {
it('should return a list of schemas', async () => {
(googleApiRequestAllItems as jest.Mock).mockResolvedValue([
{ displayName: 'Employee Info', schemaName: 'EmployeeSchema' },
{ displayName: '', schemaName: 'CustomSchema' },
]);
const result = await node.methods.loadOptions.getSchemas.call(mockThis);
expect(result).toEqual([
{ name: 'Employee Info', value: 'EmployeeSchema' },
{ name: 'CustomSchema', value: 'CustomSchema' },
]);
});
it('should correctly iterate over schemas and return expected values', async () => {
const schemas = [
{ displayName: 'Employee Info', schemaName: 'EmployeeSchema' },
{ displayName: 'Custom Schema', schemaName: 'CustomSchema' },
];
const result = schemas.map((schema) => ({
name: schema.displayName,
value: schema.schemaName,
}));
expect(result).toEqual([
{ name: 'Employee Info', value: 'EmployeeSchema' },
{ name: 'Custom Schema', value: 'CustomSchema' },
]);
});
});
describe('getOrgUnits', () => {
it('should return a list of organizational units', async () => {
(googleApiRequest as jest.Mock).mockResolvedValue({
organizationUnits: [
{ name: 'Engineering', orgUnitPath: '/engineering' },
{ name: 'HR', orgUnitPath: '/hr' },
],
});
const result = await node.methods.loadOptions.getOrgUnits.call(mockThis);
expect(result).toEqual([
{ name: 'Engineering', value: '/engineering' },
{ name: 'HR', value: '/hr' },
]);
});
});
});
describe('GSuiteAdmin Node - logic coverage', () => {
it('should apply all filters correctly into qs', () => {
const filter = {
customer: 'my_customer',
domain: 'example.com',
query: 'name:admin',
userId: 'user@example.com',
showDeleted: true,
};
const sort = {
sortRules: { orderBy: 'email', sortOrder: 'ASCENDING' },
};
const qs: Record<string, any> = {};
if (filter.customer) qs.customer = filter.customer;
if (filter.domain) qs.domain = filter.domain;
if (filter.query) {
const query = filter.query.trim();
const regex = /^(name|email):\S+$/;
if (!regex.test(query)) {
throw new NodeOperationError(
mockThis.getNode(),
'Invalid query format. Query must follow the format "displayName:<value>" or "email:<value>".',
);
}
qs.query = query;
}
if (filter.userId) qs.userKey = filter.userId;
if (filter.showDeleted) qs.showDeleted = 'true';
if (sort.sortRules) {
const { orderBy, sortOrder } = sort.sortRules;
if (orderBy) qs.orderBy = orderBy;
if (sortOrder) qs.sortOrder = sortOrder;
}
expect(qs).toEqual({
customer: 'my_customer',
domain: 'example.com',
query: 'name:admin',
userKey: 'user@example.com',
showDeleted: 'true',
orderBy: 'email',
sortOrder: 'ASCENDING',
});
});
it('should throw an error for invalid query format', () => {
const filter = {
query: 'invalidQuery',
};
const qs: Record<string, any> = {};
expect(() => {
if (filter.query) {
const query = filter.query.trim();
const regex = /^(name|email):\S+$/;
if (!regex.test(query)) {
throw new NodeOperationError(
mockThis.getNode(),
'Invalid query format. Query must follow the format "displayName:<value>" or "email:<value>".',
);
}
qs.query = query;
}
}).toThrow(
'Invalid query format. Query must follow the format "displayName:<value>" or "email:<value>".',
);
});
it('should assign my_customer when customer is not defined', () => {
const qs: Record<string, any> = {};
if (!qs.customer) qs.customer = 'my_customer';
expect(qs.customer).toBe('my_customer');
});
it('should throw an error if username is empty', () => {
const mock = { getNode: () => ({}) } as IExecuteFunctions;
expect(() => {
const username = '';
if (!username) {
throw new NodeOperationError(mock.getNode(), "The parameter 'Username' is empty", {
itemIndex: 0,
description: "Please fill in the 'Username' parameter to create the user",
});
}
}).toThrow("The parameter 'Username' is empty");
});
it('should set phones, emails, roles, and custom fields', () => {
const additionalFields = {
phoneUi: { phoneValues: [{ type: 'work', value: '123' }] },
emailUi: { emailValues: [{ address: 'test@example.com', type: 'home' }] },
roles: ['superAdmin', 'groupsAdmin'],
customFields: {
fieldValues: [{ schemaName: 'CustomSchema', fieldName: 'customField', value: 'abc' }],
},
};
const body: Record<string, any> = {};
if (additionalFields.phoneUi) {
body.phones = additionalFields.phoneUi.phoneValues;
}
if (additionalFields.emailUi) {
body.emails = additionalFields.emailUi.emailValues;
}
if (additionalFields.roles) {
const roles = additionalFields.roles;
body.roles = {
superAdmin: roles.includes('superAdmin'),
groupsAdmin: roles.includes('groupsAdmin'),
groupsReader: false,
groupsEditor: false,
userManagement: false,
helpDeskAdmin: false,
servicesAdmin: false,
inventoryReportingAdmin: false,
storageAdmin: false,
directorySyncAdmin: false,
mobileAdmin: false,
};
}
if (additionalFields.customFields) {
const customSchemas: Record<string, any> = {};
for (const field of additionalFields.customFields.fieldValues) {
if (
!field.schemaName ||
!field.fieldName ||
field.value === undefined ||
field.value === ''
) {
continue;
}
if (!customSchemas[field.schemaName]) customSchemas[field.schemaName] = {};
customSchemas[field.schemaName][field.fieldName] = field.value;
}
if (Object.keys(customSchemas).length > 0) {
body.customSchemas = customSchemas;
}
}
expect(body).toEqual({
phones: [{ type: 'work', value: '123' }],
emails: [{ address: 'test@example.com', type: 'home' }],
roles: {
superAdmin: true,
groupsAdmin: true,
groupsReader: false,
groupsEditor: false,
userManagement: false,
helpDeskAdmin: false,
servicesAdmin: false,
inventoryReportingAdmin: false,
storageAdmin: false,
directorySyncAdmin: false,
mobileAdmin: false,
},
customSchemas: {
CustomSchema: { customField: 'abc' },
},
});
});
it('should set customFieldMask and fields if projection is custom and output is select', () => {
const projection = 'custom';
const output = 'select';
const fields = ['primaryEmail'];
const qs: Record<string, any> = {
customFieldMask: ['Custom1', 'Custom2'],
};
if (projection === 'custom' && qs.customFieldMask) {
qs.customFieldMask = (qs.customFieldMask as string[]).join(',');
}
if (output === 'select') {
if (!fields.includes('id')) fields.push('id');
qs.fields = fields.join(',');
}
expect(qs).toEqual({
customFieldMask: 'Custom1,Custom2',
fields: 'primaryEmail,id',
});
});
it('should set fields for user getAll when returnAll is false', () => {
const qs: Record<string, any> = {};
const returnAll = false;
const fields = ['primaryEmail'];
const output = 'select';
const projection = 'custom';
qs.customFieldMask = ['Custom1', 'Custom2'];
if (projection === 'custom' && qs.customFieldMask) {
qs.customFieldMask = (qs.customFieldMask as string[]).join(',');
}
if (output === 'select') {
if (!fields.includes('id')) fields.push('id');
qs.fields = `users(${fields.join(',')})`;
}
if (!qs.customer) qs.customer = 'my_customer';
if (!returnAll) qs.maxResults = 50;
expect(qs).toEqual({
customFieldMask: 'Custom1,Custom2',
fields: 'users(primaryEmail,id)',
customer: 'my_customer',
maxResults: 50,
});
});
});
describe('GSuiteAdmin Node - user:create logic', () => {
it('should include changePasswordAtNextLogin when set to true in create operation', async () => {
const mockCall = jest
.fn()
.mockResolvedValue({ id: 'user-123', primaryEmail: 'test@example.com' });
(googleApiRequest as jest.Mock).mockImplementation(mockCall);
const mockContext = {
getNode: () => ({ name: 'GSuiteAdmin' }),
getNodeParameter: jest.fn((paramName: string, _index?: number) => {
switch (paramName) {
case 'resource':
return 'user';
case 'operation':
return 'create';
case 'domain':
return 'example.com';
case 'firstName':
return 'John';
case 'lastName':
return 'Doe';
case 'password':
return 'SecurePassword123!';
case 'username':
return 'johndoe';
case 'additionalFields':
return {
changePasswordAtNextLogin: true,
};
default:
return undefined;
}
}),
helpers: {
returnJsonArray: (data: any) => [data],
constructExecutionMetaData: (data: any) => data,
},
continueOnFail: () => false,
getInputData: () => [{ json: {} }],
} as unknown as IExecuteFunctions;
await new GSuiteAdmin().execute.call(mockContext);
expect(mockCall).toHaveBeenCalledWith(
'POST',
'/directory/v1/users',
expect.objectContaining({
changePasswordAtNextLogin: true,
password: 'SecurePassword123!',
primaryEmail: 'johndoe@example.com',
name: {
givenName: 'John',
familyName: 'Doe',
},
}),
{},
);
});
it('should include changePasswordAtNextLogin when set to false in create operation', async () => {
const mockCall = jest
.fn()
.mockResolvedValue({ id: 'user-124', primaryEmail: 'test2@example.com' });
(googleApiRequest as jest.Mock).mockImplementation(mockCall);
const mockContext = {
getNode: () => ({ name: 'GSuiteAdmin' }),
getNodeParameter: jest.fn((paramName: string, _index?: number) => {
switch (paramName) {
case 'resource':
return 'user';
case 'operation':
return 'create';
case 'domain':
return 'example.com';
case 'firstName':
return 'Jane';
case 'lastName':
return 'Smith';
case 'password':
return 'AnotherPassword456!';
case 'username':
return 'janesmith';
case 'additionalFields':
return {
changePasswordAtNextLogin: false,
};
default:
return undefined;
}
}),
helpers: {
returnJsonArray: (data: any) => [data],
constructExecutionMetaData: (data: any) => data,
},
continueOnFail: () => false,
getInputData: () => [{ json: {} }],
} as unknown as IExecuteFunctions;
await new GSuiteAdmin().execute.call(mockContext);
expect(mockCall).toHaveBeenCalledWith(
'POST',
'/directory/v1/users',
expect.objectContaining({
changePasswordAtNextLogin: false,
password: 'AnotherPassword456!',
}),
{},
);
});
it('should not include changePasswordAtNextLogin when undefined in create operation', async () => {
const mockCall = jest
.fn()
.mockResolvedValue({ id: 'user-125', primaryEmail: 'test3@example.com' });
(googleApiRequest as jest.Mock).mockImplementation(mockCall);
const mockContext = {
getNode: () => ({ name: 'GSuiteAdmin' }),
getNodeParameter: jest.fn((paramName: string, _index?: number) => {
switch (paramName) {
case 'resource':
return 'user';
case 'operation':
return 'create';
case 'domain':
return 'example.com';
case 'firstName':
return 'Bob';
case 'lastName':
return 'Johnson';
case 'password':
return 'Password789!';
case 'username':
return 'bjohnson';
case 'additionalFields':
return {};
default:
return undefined;
}
}),
helpers: {
returnJsonArray: (data: any) => [data],
constructExecutionMetaData: (data: any) => data,
},
continueOnFail: () => false,
getInputData: () => [{ json: {} }],
} as unknown as IExecuteFunctions;
await new GSuiteAdmin().execute.call(mockContext);
expect(mockCall).toHaveBeenCalledWith(
'POST',
'/directory/v1/users',
{
name: { familyName: 'Johnson', givenName: 'Bob' },
password: 'Password789!',
primaryEmail: 'bjohnson@example.com',
},
{},
);
});
});
describe('GSuiteAdmin Node - user:update logic', () => {
it('should build suspended, roles, and customSchemas', async () => {
const mockCall = jest.fn().mockResolvedValue([{ success: true }]);
(googleApiRequest as jest.Mock).mockImplementation(mockCall);
const mockContext = {
getNode: () => ({ name: 'GSuiteAdmin' }),
getNodeParameter: jest.fn((paramName: string) => {
switch (paramName) {
case 'resource':
return 'user';
case 'operation':
return 'update';
case 'userId':
return 'user-id-123';
case 'updateFields':
return {
suspendUi: true,
roles: ['superAdmin', 'groupsReader'],
customFields: {
fieldValues: [
{ schemaName: 'CustomSchema1', fieldName: 'fieldA', value: 'valueA' },
{ schemaName: 'CustomSchema1', fieldName: 'fieldB', value: 'valueB' },
{ schemaName: 'CustomSchema2', fieldName: 'fieldX', value: 'valueX' },
],
},
};
default:
return undefined;
}
}),
helpers: {
returnJsonArray: (data: any) => data,
constructExecutionMetaData: (data: any) => data,
},
continueOnFail: () => false,
getInputData: () => [{ json: {} }],
} as unknown as IExecuteFunctions;
await new GSuiteAdmin().execute.call(mockContext);
const calledBody = mockCall.mock.calls[0][2];
expect(calledBody.suspended).toBe(true);
expect(calledBody.roles).toEqual({
superAdmin: true,
groupsAdmin: false,
groupsReader: true,
groupsEditor: false,
userManagement: false,
helpDeskAdmin: false,
servicesAdmin: false,
inventoryReportingAdmin: false,
storageAdmin: false,
directorySyncAdmin: false,
mobileAdmin: false,
});
expect(calledBody.customSchemas).toEqual({
CustomSchema1: {
fieldA: 'valueA',
fieldB: 'valueB',
},
CustomSchema2: {
fieldX: 'valueX',
},
});
});
it('should include password and changePasswordAtNextLogin in update operation', async () => {
const mockCall = jest.fn().mockResolvedValue({ id: 'user-id-456', success: true });
(googleApiRequest as jest.Mock).mockImplementation(mockCall);
const mockContext = {
getNode: () => ({ name: 'GSuiteAdmin' }),
getNodeParameter: jest.fn((paramName: string, _index?: number) => {
switch (paramName) {
case 'resource':
return 'user';
case 'operation':
return 'update';
case 'userId':
return 'user-id-456';
case 'updateFields':
return {
password: 'NewSecurePassword123!',
changePasswordAtNextLogin: true,
};
default:
return undefined;
}
}),
helpers: {
returnJsonArray: (data: any) => [data],
constructExecutionMetaData: (data: any) => data,
},
continueOnFail: () => false,
getInputData: () => [{ json: {} }],
} as unknown as IExecuteFunctions;
await new GSuiteAdmin().execute.call(mockContext);
expect(mockCall).toHaveBeenCalledWith(
'PUT',
'/directory/v1/users/user-id-456',
expect.objectContaining({
password: 'NewSecurePassword123!',
changePasswordAtNextLogin: true,
}),
{},
);
});
it('should include changePasswordAtNextLogin set to false in update operation', async () => {
const mockCall = jest.fn().mockResolvedValue({ id: 'user-id-999', success: true });
(googleApiRequest as jest.Mock).mockImplementation(mockCall);
const mockContext = {
getNode: () => ({ name: 'GSuiteAdmin' }),
getNodeParameter: jest.fn((paramName: string) => {
switch (paramName) {
case 'resource':
return 'user';
case 'operation':
return 'update';
case 'userId':
return 'user-id-999';
case 'updateFields':
return {
changePasswordAtNextLogin: false,
password: 'TestPassword!',
};
default:
return undefined;
}
}),
helpers: {
returnJsonArray: (data: any) => [data],
constructExecutionMetaData: (data: any) => data,
},
continueOnFail: () => false,
getInputData: () => [{ json: {} }],
} as unknown as IExecuteFunctions;
await new GSuiteAdmin().execute.call(mockContext);
expect(mockCall).toHaveBeenCalledWith(
'PUT',
'/directory/v1/users/user-id-999',
expect.objectContaining({
password: 'TestPassword!',
changePasswordAtNextLogin: false,
}),
{},
);
});
it('should throw error for invalid custom fields', async () => {
const mockCall = jest.fn();
(googleApiRequest as jest.Mock).mockImplementation(mockCall);
const mockContextInvalidFields = {
getNode: () => ({ name: 'GSuiteAdmin' }),
getNodeParameter: jest.fn((paramName: string) => {
switch (paramName) {
case 'resource':
return 'user';
case 'operation':
return 'update';
case 'userId':
return 'user-id-456';
case 'updateFields':
return {
customFields: {
fieldValues: [
{ schemaName: '', fieldName: 'valid', value: 'ok' },
{ schemaName: 'ValidSchema', fieldName: 'valid', value: 'ok' },
],
},
};
default:
return undefined;
}
}),
helpers: {
returnJsonArray: (data: any) => data,
constructExecutionMetaData: (data: any) => data,
},
continueOnFail: () => false,
getInputData: () => [{ json: {} }],
} as unknown as IExecuteFunctions;
await expect(new GSuiteAdmin().execute.call(mockContextInvalidFields)).rejects.toThrow(
'Invalid custom field data',
);
expect(mockCall).not.toHaveBeenCalled();
});
it('should throw an error if username is empty', () => {
const mock = { getNode: () => ({}) } as IExecuteFunctions;
expect(() => {
const username = '';
if (!username) {
throw new NodeOperationError(mock.getNode(), "The parameter 'Username' is empty", {
itemIndex: 0,
description: "Please fill in the 'Username' parameter to create the user",
});
}
}).toThrow("The parameter 'Username' is empty");
});
});
describe('GSuiteAdmin Node - Error Handling', () => {
it('should throw a NodeOperationError if the error is an instance of NodeOperationError', async () => {
const mockContext = {
getNode: () => ({ name: 'GSuiteAdmin' }),
continueOnFail: () => false,
helpers: {
constructExecutionMetaData: jest.fn(),
returnJsonArray: jest.fn(),
},
} as unknown as IExecuteFunctions;
const error = new NodeOperationError(mockContext.getNode(), 'Some error message');
await expect(async () => {
throw error;
}).rejects.toThrow(NodeOperationError);
});
it('should handle error when continueOnFail is true and constructExecutionMetaData is called', async () => {
const mockContext = {
getNode: () => ({ name: 'GSuiteAdmin' }),
continueOnFail: () => true,
helpers: {
constructExecutionMetaData: jest.fn().mockReturnValue([{ message: 'mock error data' }]),
returnJsonArray: jest.fn().mockReturnValue([]),
},
} as unknown as IExecuteFunctions;
const error = new Error('Some error message');
await expect(async () => {
if (error instanceof NodeOperationError) {
throw error;
}
if (mockContext.continueOnFail()) {
const executionErrorData = mockContext.helpers.constructExecutionMetaData(
mockContext.helpers.returnJsonArray({
message: 'Operation "update" failed for resource "user".',
description: error.message,
}),
{ itemData: { item: 0 } },
);
if (executionErrorData) {
returnData.push(...executionErrorData);
} else {
console.error('executionErrorData is not iterable:', executionErrorData);
}
}
throw new NodeOperationError(
mockContext.getNode(),
'Operation "update" failed for resource "user".',
{
description: `Please check the input parameters and ensure the API request is correctly formatted. Details: ${error.message}`,
itemIndex: 0,
},
);
}).rejects.toThrow(NodeOperationError);
});
it('should throw a NodeOperationError if an unknown error is thrown and continueOnFail is false', async () => {
const mockContext = {
getNode: () => ({ name: 'GSuiteAdmin' }),
continueOnFail: () => false,
helpers: {
constructExecutionMetaData: jest.fn(),
returnJsonArray: jest.fn(),
},
} as unknown as IExecuteFunctions;
const error = new Error('Some unknown error');
await expect(async () => {
if (error instanceof NodeOperationError) {
throw error;
}
if (!mockContext.continueOnFail()) {
throw new NodeOperationError(
mockContext.getNode(),
'Operation "update" failed for resource "user".',
{
description: `Please check the input parameters and ensure the API request is correctly formatted. Details: ${error.message}`,
itemIndex: 0,
},
);
}
}).rejects.toThrow(NodeOperationError);
});
});
@@ -0,0 +1,173 @@
import type { IExecuteFunctions, ILoadOptionsFunctions } from 'n8n-workflow';
import { NodeApiError } from 'n8n-workflow';
import { googleApiRequest, googleApiRequestAllItems } from '../GenericFunctions';
describe('Google GSuiteAdmin Node', () => {
let mockContext: IExecuteFunctions | ILoadOptionsFunctions;
beforeEach(() => {
mockContext = {
helpers: {
httpRequestWithAuthentication: jest.fn(),
},
getNode: jest.fn(),
} as unknown as IExecuteFunctions | ILoadOptionsFunctions;
jest.clearAllMocks();
});
it('should make a successful API request with default options', async () => {
(mockContext.helpers.httpRequestWithAuthentication as jest.Mock).mockResolvedValueOnce({
success: true,
});
const result = await googleApiRequest.call(mockContext, 'GET', '/example/resource');
expect(mockContext.helpers.httpRequestWithAuthentication).toHaveBeenCalledWith(
'gSuiteAdminOAuth2Api',
expect.objectContaining({
method: 'GET',
url: 'https://www.googleapis.com/admin/example/resource',
headers: { 'Content-Type': 'application/json' },
json: true,
qs: {},
}),
);
expect(result).toEqual({ success: true });
});
it('should omit the body if it is empty', async () => {
(mockContext.helpers.httpRequestWithAuthentication as jest.Mock).mockResolvedValueOnce({
success: true,
});
await googleApiRequest.call(mockContext, 'GET', '/example/resource', {});
expect(mockContext.helpers.httpRequestWithAuthentication).toHaveBeenCalledWith(
'gSuiteAdminOAuth2Api',
expect.not.objectContaining({ body: expect.anything() }),
);
});
it('should throw a NodeApiError if the request fails', async () => {
const errorResponse = { message: 'API Error' };
(mockContext.helpers.httpRequestWithAuthentication as jest.Mock).mockRejectedValueOnce(
errorResponse,
);
await expect(googleApiRequest.call(mockContext, 'GET', '/example/resource')).rejects.toThrow(
NodeApiError,
);
expect(mockContext.getNode).toHaveBeenCalled();
expect(mockContext.helpers.httpRequestWithAuthentication).toHaveBeenCalled();
});
it('should return all items across multiple pages', async () => {
(mockContext.helpers.httpRequestWithAuthentication as jest.Mock)
.mockResolvedValueOnce({
nextPageToken: 'pageToken1',
items: [{ id: '1' }, { id: '2' }],
})
.mockResolvedValueOnce({
nextPageToken: 'pageToken2',
items: [{ id: '3' }, { id: '4' }],
})
.mockResolvedValueOnce({
nextPageToken: '',
items: [{ id: '5' }],
});
const result = await googleApiRequestAllItems.call(
mockContext,
'items',
'GET',
'/example/resource',
);
expect(result).toEqual([{ id: '1' }, { id: '2' }, { id: '3' }, { id: '4' }, { id: '5' }]);
expect(mockContext.helpers.httpRequestWithAuthentication).toHaveBeenCalledTimes(3);
expect(mockContext.helpers.httpRequestWithAuthentication).toHaveBeenNthCalledWith(
1,
'gSuiteAdminOAuth2Api',
expect.objectContaining({
method: 'GET',
qs: { maxResults: 100, pageToken: '' },
headers: { 'Content-Type': 'application/json' },
url: 'https://www.googleapis.com/admin/example/resource',
json: true,
}),
);
expect(mockContext.helpers.httpRequestWithAuthentication).toHaveBeenNthCalledWith(
2,
'gSuiteAdminOAuth2Api',
expect.objectContaining({
method: 'GET',
qs: { maxResults: 100, pageToken: '' },
headers: { 'Content-Type': 'application/json' },
url: 'https://www.googleapis.com/admin/example/resource',
json: true,
}),
);
expect(mockContext.helpers.httpRequestWithAuthentication).toHaveBeenNthCalledWith(
3,
'gSuiteAdminOAuth2Api',
expect.objectContaining({
method: 'GET',
qs: { maxResults: 100, pageToken: '' },
headers: { 'Content-Type': 'application/json' },
url: 'https://www.googleapis.com/admin/example/resource',
json: true,
}),
);
});
it('should handle single-page responses', async () => {
(mockContext.helpers.httpRequestWithAuthentication as jest.Mock).mockResolvedValueOnce({
nextPageToken: '',
items: [{ id: '1' }, { id: '2' }],
});
const result = await googleApiRequestAllItems.call(
mockContext,
'items',
'GET',
'/example/resource',
);
expect(result).toEqual([{ id: '1' }, { id: '2' }]);
expect(mockContext.helpers.httpRequestWithAuthentication).toHaveBeenCalledTimes(1);
});
it('should handle empty responses', async () => {
(mockContext.helpers.httpRequestWithAuthentication as jest.Mock).mockResolvedValueOnce({
nextPageToken: '',
items: [],
});
const result = await googleApiRequestAllItems.call(
mockContext,
'items',
'GET',
'/example/resource',
);
expect(result).toEqual([]);
expect(mockContext.helpers.httpRequestWithAuthentication).toHaveBeenCalledTimes(1);
});
it('should throw a NodeApiError if a request fails', async () => {
const errorResponse = { message: 'API Error' };
(mockContext.helpers.httpRequestWithAuthentication as jest.Mock).mockRejectedValueOnce(
errorResponse,
);
await expect(
googleApiRequestAllItems.call(mockContext, 'items', 'GET', '/example/resource'),
).rejects.toThrow();
expect(mockContext.getNode).toHaveBeenCalled();
expect(mockContext.helpers.httpRequestWithAuthentication).toHaveBeenCalledTimes(1);
});
});
@@ -0,0 +1,104 @@
import type { ILoadOptionsFunctions } from 'n8n-workflow';
import { googleApiRequest, googleApiRequestAllItems } from '../GenericFunctions';
import { searchUsers, searchGroups, searchDevices } from '../SearchFunctions';
jest.mock('../GenericFunctions');
describe('searchFunctions', () => {
let mockContext: ILoadOptionsFunctions;
beforeEach(() => {
mockContext = {
getNodeParameter: jest.fn(),
} as unknown as ILoadOptionsFunctions;
jest.clearAllMocks();
});
describe('searchUsers', () => {
it('should return formatted user search results', async () => {
(googleApiRequestAllItems as jest.Mock).mockResolvedValueOnce([
{ id: '123', name: { fullName: 'John Doe' } },
{ id: '456' },
]);
const result = await searchUsers.call(mockContext);
expect(googleApiRequestAllItems).toHaveBeenCalledWith(
expect.anything(),
'GET',
'/directory/v1/users',
{},
{ customer: 'my_customer' },
);
expect(result).toEqual({
results: [
{ name: 'John Doe', value: '123' },
{ name: '456', value: '456' },
],
});
});
it('should return an empty array if no users found', async () => {
(googleApiRequestAllItems as jest.Mock).mockResolvedValueOnce([]);
const result = await searchUsers.call(mockContext);
expect(result).toEqual({ results: [] });
});
});
describe('searchGroups', () => {
it('should return formatted group search results', async () => {
(googleApiRequestAllItems as jest.Mock).mockResolvedValueOnce([
{ id: 'group1', name: 'Group One' },
{ id: 'group2', email: 'group@example.com' },
{ id: 'group3' },
]);
const result = await searchGroups.call(mockContext);
expect(result).toEqual({
results: [
{ name: 'Group One', value: 'group1' },
{ name: 'group@example.com', value: 'group2' },
{ name: 'Unnamed Group', value: 'group3' },
],
});
});
it('should return empty results if no groups found', async () => {
(googleApiRequestAllItems as jest.Mock).mockResolvedValueOnce([]);
const result = await searchGroups.call(mockContext);
expect(result).toEqual({ results: [] });
});
});
describe('searchDevices', () => {
it('should return formatted device search results', async () => {
(googleApiRequest as jest.Mock).mockResolvedValueOnce({
chromeosdevices: [{ deviceId: 'dev1', serialNumber: 'SN123' }, { deviceId: 'Dev2' }],
});
const result = await searchDevices.call(mockContext);
expect(googleApiRequest).toHaveBeenCalledWith(
'GET',
'/directory/v1/customer/my_customer/devices/chromeos/',
{},
{ customerId: 'my_customer' },
);
expect(result).toEqual({
results: [
{ name: 'SN123', value: 'dev1' },
{ name: 'Dev2', value: 'Dev2' },
],
});
});
it('should return empty results if no devices found', async () => {
(googleApiRequest as jest.Mock).mockResolvedValueOnce({ chromeosdevices: [] });
const result = await searchDevices.call(mockContext);
expect(result).toEqual({ results: [] });
});
});
});
@@ -0,0 +1,24 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import nock from 'nock';
describe('Google GSuiteAdmin Node', () => {
beforeEach(() => {
nock.disableNetConnect();
nock('https://www.googleapis.com/admin')
.post(
'/directory/v1/customer/my_customer/devices/chromeos/9140fcff-7ba7-4324-8552-f7de68481b4c/action',
{
action: 'reenable',
},
)
.reply(200, {
kind: 'admin#directory#chromeosdeviceAction',
action: 'reenable',
status: 'SUCCESS',
});
});
new NodeTestHarness().setupTests({
workflowFiles: ['changeStatus.workflow.json'],
});
});
@@ -0,0 +1,59 @@
{
"nodes": [
{
"parameters": {},
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [-180, 240],
"id": "db450654-d59c-4fb4-a06c-af7b971f0c14",
"name": "When clicking Execute workflow"
},
{
"parameters": {
"resource": "device",
"operation": "changeStatus",
"deviceId": {
"__rl": true,
"value": "9140fcff-7ba7-4324-8552-f7de68481b4c",
"mode": "list",
"cachedResultName": "5CC115NN33"
}
},
"type": "n8n-nodes-base.gSuiteAdmin",
"typeVersion": 1,
"position": [-320, 680],
"id": "d441de38-e340-495d-8177-f8bd8bb33e50",
"name": "Change Status",
"credentials": {
"gSuiteAdminOAuth2Api": {
"id": "OXfPMaggXFJ0RLkw",
"name": "Google Workspace Admin account"
}
}
}
],
"connections": {
"When clicking Execute workflow": {
"main": [
[
{
"node": "Change Status",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Change Status": [
{
"json": {
"kind": "admin#directory#chromeosdeviceAction",
"action": "reenable",
"status": "SUCCESS"
}
}
]
}
}
@@ -0,0 +1,36 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import nock from 'nock';
describe('Google GSuiteAdmin Node', () => {
beforeEach(() => {
nock.disableNetConnect();
nock('https://www.googleapis.com/admin')
.get(
'/directory/v1/customer/my_customer/devices/chromeos/9999ffff-7aa7-4444-8555-f7de48484b4a?projection=basic',
)
.reply(200, {
kind: 'admin#directory#chromeosdevice',
etag: '"example"',
deviceId: '9999ffff-7aa7-4444-8555-f7de48484b4a',
serialNumber: '5DD1155DD44',
status: 'DISABLED',
lastSync: '2025-02-12T07:17:16.950Z',
annotatedUser: 'my user',
annotatedLocation: 'test',
annotatedAssetId: '1234567788',
notes: 'test',
orgUnitPath: '/',
orgUnitId: '00pp8a2z1uu85pp',
extendedSupportEligible: false,
chromeOsType: 'chromeOs',
diskSpaceUsage: {
capacityBytes: '549755813888',
usedBytes: '549755813888',
},
});
});
new NodeTestHarness().setupTests({
workflowFiles: ['get.workflow.json'],
});
});
@@ -0,0 +1,73 @@
{
"nodes": [
{
"parameters": {},
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [120, 700],
"id": "0ffead0b-d690-48b8-b406-bea5e0029c15",
"name": "When clicking Execute workflow"
},
{
"parameters": {
"resource": "device",
"deviceId": {
"__rl": true,
"value": "9999ffff-7aa7-4444-8555-f7de48484b4a",
"mode": "list",
"cachedResultName": "5DD1155DD44"
}
},
"type": "n8n-nodes-base.gSuiteAdmin",
"typeVersion": 1,
"position": [0, 1120],
"id": "cda57e63-1620-4f75-b11e-48b83565ad80",
"name": "Get Device",
"credentials": {
"gSuiteAdminOAuth2Api": {
"id": "OXfPMaggXFJ0RLkw",
"name": "Google Workspace Admin account"
}
}
}
],
"connections": {
"When clicking Execute workflow": {
"main": [
[
{
"node": "Get Device",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Get Device": [
{
"json": {
"kind": "admin#directory#chromeosdevice",
"etag": "\"example\"",
"deviceId": "9999ffff-7aa7-4444-8555-f7de48484b4a",
"serialNumber": "5DD1155DD44",
"status": "DISABLED",
"lastSync": "2025-02-12T07:17:16.950Z",
"annotatedUser": "my user",
"annotatedLocation": "test",
"annotatedAssetId": "1234567788",
"notes": "test",
"orgUnitPath": "/",
"orgUnitId": "00pp8a2z1uu85pp",
"extendedSupportEligible": false,
"chromeOsType": "chromeOs",
"diskSpaceUsage": {
"capacityBytes": "549755813888",
"usedBytes": "549755813888"
}
}
}
]
}
}
@@ -0,0 +1,28 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import nock from 'nock';
describe('Google GSuiteAdmin Node', () => {
beforeEach(() => {
nock.disableNetConnect();
nock('https://www.googleapis.com/admin')
.get('/directory/v1/customer/my_customer/devices/chromeos/')
.query({
customer: 'my_customer',
includeChildOrgunits: false,
maxResults: 100,
orderBy: 'notes',
orgUnitPath: '/admin-google Testing OU/Child OU',
projection: 'basic',
})
.reply(200, [
{
kind: 'admin#directory#chromeosdevices',
etag: '"example"',
},
]);
});
new NodeTestHarness().setupTests({
workflowFiles: ['getAll.workflow.json'],
});
});
@@ -0,0 +1,61 @@
{
"nodes": [
{
"parameters": {},
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [120, 700],
"id": "0e76b314-4994-4141-975f-9614c6094c80",
"name": "When clicking Execute workflow"
},
{
"parameters": {
"resource": "device",
"operation": "getAll",
"filter": {
"orgUnitPath": "/admin-google Testing OU/Child OU"
},
"sort": {
"sortRules": {
"orderBy": "notes",
"sortBy": "ascending"
}
}
},
"type": "n8n-nodes-base.gSuiteAdmin",
"typeVersion": 1,
"position": [40, 1120],
"id": "b8a51950-2fdb-4161-9dc3-09f73de5a45b",
"name": "Get Many Device",
"credentials": {
"gSuiteAdminOAuth2Api": {
"id": "OXfPMaggXFJ0RLkw",
"name": "Google Workspace Admin account"
}
}
}
],
"connections": {
"When clicking Execute workflow": {
"main": [
[
{
"node": "Get Many Device",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Get Many Device": [
{
"json": {
"kind": "admin#directory#chromeosdevices",
"etag": "\"example\""
}
}
]
}
}
@@ -0,0 +1,620 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import nock from 'nock';
describe('Google GSuiteAdmin Node', () => {
beforeEach(() => {
nock.disableNetConnect();
nock('https://www.googleapis.com/admin')
.put(
'/directory/v1/customer/my_customer/devices/chromeos/9990fpff-8ba8-4444-8555-f7ee88881b4c',
)
.reply(200, {
kind: 'admin#directory#chromeosdevice',
etag: '"example"',
deviceId: '9990fpff-8ba8-4444-8555-f7ee88881b4c',
serialNumber: '5CC115NN33',
status: 'DISABLED',
lastSync: '2025-02-12T07:17:16.950Z',
annotatedUser: 'my user',
annotatedLocation: 'test',
annotatedAssetId: '1234567788',
notes: 'test',
model: 'Test Model',
osVersion: '129.0.6668.99',
platformVersion: '16002.51.0 (Official Build) stable-channel reven',
firmwareVersion: 'FirmwareNotParsed',
macAddress: '666c8888ffccf',
lastEnrollmentTime: '2025-02-10T17:03:10.324Z',
firstEnrollmentTime: '2025-02-10T17:03:10.324Z',
orgUnitPath: '/',
orgUnitId: '00pp88a2z2uu88pp',
recentUsers: [
{
type: 'USER_TYPE_MANAGED',
email: 'admin-google@example.com',
},
],
activeTimeRanges: [
{
date: '2025-02-10',
activeTime: 300000,
},
{
date: '2025-02-11',
activeTime: 1920025,
},
{
date: '2025-02-12',
activeTime: 30000,
},
],
tpmVersionInfo: {
family: '0',
specLevel: '0',
manufacturer: '0',
tpmModel: '0',
firmwareVersion: '0',
vendorSpecific: '',
},
cpuStatusReports: [
{
reportTime: '2025-02-10T17:03:13.233Z',
cpuUtilizationPercentageInfo: [12],
},
{
reportTime: '2025-02-10T17:04:13.233Z',
cpuTemperatureInfo: [
{
temperature: 42,
label: 'edge\n',
},
{
temperature: 42,
label: 'Tctl\n',
},
{
temperature: 43,
label: 'acpitz\n',
},
],
},
{
reportTime: '2025-02-10T17:11:01.943Z',
cpuUtilizationPercentageInfo: [28],
},
{
reportTime: '2025-02-10T17:12:02.223Z',
cpuTemperatureInfo: [
{
temperature: 42,
label: 'edge\n',
},
{
temperature: 51,
label: 'Tctl\n',
},
{
temperature: 43,
label: 'acpitz\n',
},
],
},
{
reportTime: '2025-02-10T17:47:32.621Z',
cpuUtilizationPercentageInfo: [28],
},
{
reportTime: '2025-02-10T17:48:42.770Z',
cpuTemperatureInfo: [
{
temperature: 43,
label: 'edge\n',
},
{
temperature: 44,
label: 'Tctl\n',
},
{
temperature: 44,
label: 'acpitz\n',
},
],
},
{
reportTime: '2025-02-10T18:56:24.294Z',
cpuUtilizationPercentageInfo: [29],
},
{
reportTime: '2025-02-10T18:57:27.841Z',
cpuTemperatureInfo: [
{
temperature: 34,
label: 'edge\n',
},
{
temperature: 35,
label: 'Tctl\n',
},
{
temperature: 35,
label: 'acpitz\n',
},
],
},
{
reportTime: '2025-02-10T23:04:56.582Z',
cpuUtilizationPercentageInfo: [27],
},
{
reportTime: '2025-02-10T23:05:56.563Z',
cpuTemperatureInfo: [
{
temperature: 27,
label: 'edge\n',
},
{
temperature: 28,
label: 'Tctl\n',
},
{
temperature: 27,
label: 'acpitz\n',
},
],
},
{
reportTime: '2025-02-10T23:56:47.138Z',
cpuUtilizationPercentageInfo: [28],
},
{
reportTime: '2025-02-10T23:57:50.717Z',
cpuTemperatureInfo: [
{
temperature: 39,
label: 'edge\n',
},
{
temperature: 39,
label: 'Tctl\n',
},
{
temperature: 40,
label: 'acpitz\n',
},
],
},
{
reportTime: '2025-02-11T07:49:44.333Z',
cpuUtilizationPercentageInfo: [26],
},
{
reportTime: '2025-02-11T07:50:48.473Z',
cpuTemperatureInfo: [
{
temperature: 26,
label: 'edge\n',
},
{
temperature: 27,
label: 'Tctl\n',
},
{
temperature: 27,
label: 'acpitz\n',
},
],
},
{
reportTime: '2025-02-11T15:46:23.530Z',
cpuUtilizationPercentageInfo: [27],
},
{
reportTime: '2025-02-11T15:47:22.723Z',
cpuTemperatureInfo: [
{
temperature: 27,
label: 'edge\n',
},
{
temperature: 28,
label: 'Tctl\n',
},
{
temperature: 27,
label: 'acpitz\n',
},
],
},
{
reportTime: '2025-02-11T15:52:40.368Z',
cpuUtilizationPercentageInfo: [28],
},
{
reportTime: '2025-02-11T15:53:41.233Z',
cpuTemperatureInfo: [
{
temperature: 34,
label: 'edge\n',
},
{
temperature: 35,
label: 'Tctl\n',
},
{
temperature: 35,
label: 'acpitz\n',
},
],
},
{
reportTime: '2025-02-11T16:06:07.349Z',
cpuUtilizationPercentageInfo: [30],
},
{
reportTime: '2025-02-11T16:07:07.921Z',
cpuTemperatureInfo: [
{
temperature: 39,
label: 'edge\n',
},
{
temperature: 39,
label: 'Tctl\n',
},
{
temperature: 40,
label: 'acpitz\n',
},
],
},
{
reportTime: '2025-02-11T16:13:28.511Z',
cpuUtilizationPercentageInfo: [25],
},
{
reportTime: '2025-02-11T16:14:27.628Z',
cpuTemperatureInfo: [
{
temperature: 36,
label: 'edge\n',
},
{
temperature: 37,
label: 'Tctl\n',
},
{
temperature: 37,
label: 'acpitz\n',
},
],
},
{
reportTime: '2025-02-11T16:17:06.188Z',
cpuUtilizationPercentageInfo: [27],
},
{
reportTime: '2025-02-11T16:18:06.375Z',
cpuTemperatureInfo: [
{
temperature: 40,
label: 'edge\n',
},
{
temperature: 41,
label: 'Tctl\n',
},
{
temperature: 42,
label: 'acpitz\n',
},
],
},
{
reportTime: '2025-02-11T16:36:20.232Z',
cpuUtilizationPercentageInfo: [27],
},
{
reportTime: '2025-02-11T16:37:20.599Z',
cpuTemperatureInfo: [
{
temperature: 45,
label: 'edge\n',
},
{
temperature: 58,
label: 'Tctl\n',
},
{
temperature: 45,
label: 'acpitz\n',
},
],
},
{
reportTime: '2025-02-11T16:48:45.267Z',
cpuUtilizationPercentageInfo: [27],
},
{
reportTime: '2025-02-11T16:49:44.854Z',
cpuTemperatureInfo: [
{
temperature: 42,
label: 'edge\n',
},
{
temperature: 44,
label: 'Tctl\n',
},
{
temperature: 44,
label: 'acpitz\n',
},
],
},
{
reportTime: '2025-02-12T06:35:29.337Z',
cpuUtilizationPercentageInfo: [30],
},
{
reportTime: '2025-02-12T06:36:28.433Z',
cpuTemperatureInfo: [
{
temperature: 42,
label: 'edge\n',
},
{
temperature: 42,
label: 'Tctl\n',
},
{
temperature: 42,
label: 'acpitz\n',
},
],
},
],
systemRamTotal: '16089374720',
systemRamFreeReports: [
{
reportTime: '2025-02-10T17:03:13.230Z',
systemRamFreeInfo: ['13905453056'],
},
{
reportTime: '2025-02-10T17:11:01.697Z',
systemRamFreeInfo: ['15221055488'],
},
{
reportTime: '2025-02-10T17:47:32.153Z',
systemRamFreeInfo: ['15237283840'],
},
{
reportTime: '2025-02-10T18:56:23.878Z',
systemRamFreeInfo: ['15228760064'],
},
{
reportTime: '2025-02-10T23:04:56.127Z',
systemRamFreeInfo: ['15228022784'],
},
{
reportTime: '2025-02-10T23:56:46.839Z',
systemRamFreeInfo: ['15226499072'],
},
{
reportTime: '2025-02-11T07:49:43.939Z',
systemRamFreeInfo: ['15229087744'],
},
{
reportTime: '2025-02-11T15:46:23.165Z',
systemRamFreeInfo: ['15226187776'],
},
{
reportTime: '2025-02-11T15:52:39.966Z',
systemRamFreeInfo: ['15226843136'],
},
{
reportTime: '2025-02-11T16:06:06.871Z',
systemRamFreeInfo: ['15225753600'],
},
{
reportTime: '2025-02-11T16:13:28.176Z',
systemRamFreeInfo: ['15228182528'],
},
{
reportTime: '2025-02-11T16:17:05.936Z',
systemRamFreeInfo: ['15223095296'],
},
{
reportTime: '2025-02-11T16:36:19.897Z',
systemRamFreeInfo: ['15226126336'],
},
{
reportTime: '2025-02-11T16:48:44.934Z',
systemRamFreeInfo: ['15226707968'],
},
{
reportTime: '2025-02-12T06:35:28.949Z',
systemRamFreeInfo: ['15222706176'],
},
],
diskVolumeReports: [
{
volumeInfo: [
{
volumeId: '/media/archive',
storageTotal: '8044687360',
storageFree: '8044687360',
},
{
volumeId: '/media/removable',
storageTotal: '8044687360',
storageFree: '8044687360',
},
],
},
],
lastKnownNetwork: [
{
ipAddress: '192.168.0.106',
wanIpAddress: '87.121.13.137',
},
],
cpuInfo: [
{
model: 'AMD Ryzen 5 4500U with Radeon Graphics',
architecture: 'x64',
maxClockSpeedKhz: 2375000,
logicalCpus: [
{
maxScalingFrequencyKhz: 2375000,
currentScalingFrequencyKhz: 1397253,
idleDuration: '60s',
cStates: [
{
displayName: 'C3',
sessionDuration: '59.509354s',
},
{
displayName: 'C1',
sessionDuration: '1.338153s',
},
{
displayName: 'C2',
sessionDuration: '0.241264s',
},
{
displayName: 'POLL',
sessionDuration: '0.004477s',
},
],
},
{
maxScalingFrequencyKhz: 2375000,
currentScalingFrequencyKhz: 1397372,
idleDuration: '60s',
cStates: [
{
displayName: 'C3',
sessionDuration: '58.861175s',
},
{
displayName: 'C1',
sessionDuration: '1.335068s',
},
{
displayName: 'C2',
sessionDuration: '0.761853s',
},
{
displayName: 'POLL',
sessionDuration: '0.007583s',
},
],
},
{
maxScalingFrequencyKhz: 2375000,
currentScalingFrequencyKhz: 1397454,
idleDuration: '58s',
cStates: [
{
displayName: 'C3',
sessionDuration: '57.457528s',
},
{
displayName: 'C1',
sessionDuration: '1.280076s',
},
{
displayName: 'C2',
sessionDuration: '0.167642s',
},
{
displayName: 'POLL',
sessionDuration: '0.003444s',
},
],
},
{
maxScalingFrequencyKhz: 2375000,
currentScalingFrequencyKhz: 1397348,
idleDuration: '59s',
cStates: [
{
displayName: 'C3',
sessionDuration: '58.906343s',
},
{
displayName: 'C1',
sessionDuration: '1.101873s',
},
{
displayName: 'C2',
sessionDuration: '0.119013s',
},
{
displayName: 'POLL',
sessionDuration: '0.009095s',
},
],
},
{
maxScalingFrequencyKhz: 2375000,
currentScalingFrequencyKhz: 1383188,
idleDuration: '60s',
cStates: [
{
displayName: 'C3',
sessionDuration: '59.476621s',
},
{
displayName: 'C1',
sessionDuration: '1.048691s',
},
{
displayName: 'C2',
sessionDuration: '0.192808s',
},
{
displayName: 'POLL',
sessionDuration: '0.003546s',
},
],
},
{
maxScalingFrequencyKhz: 2375000,
currentScalingFrequencyKhz: 1397437,
idleDuration: '60s',
cStates: [
{
displayName: 'C3',
sessionDuration: '60.155800s',
},
{
displayName: 'C1',
sessionDuration: '0.681644s',
},
{
displayName: 'C2',
sessionDuration: '0.143131s',
},
{
displayName: 'POLL',
sessionDuration: '0.004276s',
},
],
},
],
},
],
extendedSupportEligible: false,
chromeOsType: 'chromeOsFlex',
diskSpaceUsage: {
capacityBytes: '549755813888',
usedBytes: '85613068288',
},
});
});
new NodeTestHarness().setupTests({
workflowFiles: ['update.workflow.json'],
});
});
@@ -0,0 +1,661 @@
{
"nodes": [
{
"parameters": {},
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [120, 700],
"id": "0e76b314-4994-4141-975f-9614c6094c80",
"name": "When clicking Execute workflow"
},
{
"parameters": {
"resource": "device",
"operation": "update",
"deviceId": {
"__rl": true,
"value": "9990fpff-8ba8-4444-8555-f7ee88881b4c",
"mode": "list",
"cachedResultName": "5CC115NN33"
},
"updateOptions": {
"notes": "test"
}
},
"type": "n8n-nodes-base.gSuiteAdmin",
"typeVersion": 1,
"position": [40, 1140],
"id": "52f7a4b5-7ab5-4bd1-b6eb-230341ab6057",
"name": "Update Device",
"credentials": {
"gSuiteAdminOAuth2Api": {
"id": "OXfPMaggXFJ0RLkw",
"name": "Google Workspace Admin account"
}
}
}
],
"connections": {
"When clicking Execute workflow": {
"main": [
[
{
"node": "Update Device",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Update Device": [
{
"json": {
"kind": "admin#directory#chromeosdevice",
"etag": "\"example\"",
"deviceId": "9990fpff-8ba8-4444-8555-f7ee88881b4c",
"serialNumber": "5CC115NN33",
"status": "DISABLED",
"lastSync": "2025-02-12T07:17:16.950Z",
"annotatedUser": "my user",
"annotatedLocation": "test",
"annotatedAssetId": "1234567788",
"notes": "test",
"model": "Test Model",
"osVersion": "129.0.6668.99",
"platformVersion": "16002.51.0 (Official Build) stable-channel reven",
"firmwareVersion": "FirmwareNotParsed",
"macAddress": "666c8888ffccf",
"lastEnrollmentTime": "2025-02-10T17:03:10.324Z",
"firstEnrollmentTime": "2025-02-10T17:03:10.324Z",
"orgUnitPath": "/",
"orgUnitId": "00pp88a2z2uu88pp",
"recentUsers": [
{
"type": "USER_TYPE_MANAGED",
"email": "admin-google@example.com"
}
],
"activeTimeRanges": [
{
"date": "2025-02-10",
"activeTime": 300000
},
{
"date": "2025-02-11",
"activeTime": 1920025
},
{
"date": "2025-02-12",
"activeTime": 30000
}
],
"tpmVersionInfo": {
"family": "0",
"specLevel": "0",
"manufacturer": "0",
"tpmModel": "0",
"firmwareVersion": "0",
"vendorSpecific": ""
},
"cpuStatusReports": [
{
"reportTime": "2025-02-10T17:03:13.233Z",
"cpuUtilizationPercentageInfo": [12]
},
{
"reportTime": "2025-02-10T17:04:13.233Z",
"cpuTemperatureInfo": [
{
"temperature": 42,
"label": "edge\n"
},
{
"temperature": 42,
"label": "Tctl\n"
},
{
"temperature": 43,
"label": "acpitz\n"
}
]
},
{
"reportTime": "2025-02-10T17:11:01.943Z",
"cpuUtilizationPercentageInfo": [28]
},
{
"reportTime": "2025-02-10T17:12:02.223Z",
"cpuTemperatureInfo": [
{
"temperature": 42,
"label": "edge\n"
},
{
"temperature": 51,
"label": "Tctl\n"
},
{
"temperature": 43,
"label": "acpitz\n"
}
]
},
{
"reportTime": "2025-02-10T17:47:32.621Z",
"cpuUtilizationPercentageInfo": [28]
},
{
"reportTime": "2025-02-10T17:48:42.770Z",
"cpuTemperatureInfo": [
{
"temperature": 43,
"label": "edge\n"
},
{
"temperature": 44,
"label": "Tctl\n"
},
{
"temperature": 44,
"label": "acpitz\n"
}
]
},
{
"reportTime": "2025-02-10T18:56:24.294Z",
"cpuUtilizationPercentageInfo": [29]
},
{
"reportTime": "2025-02-10T18:57:27.841Z",
"cpuTemperatureInfo": [
{
"temperature": 34,
"label": "edge\n"
},
{
"temperature": 35,
"label": "Tctl\n"
},
{
"temperature": 35,
"label": "acpitz\n"
}
]
},
{
"reportTime": "2025-02-10T23:04:56.582Z",
"cpuUtilizationPercentageInfo": [27]
},
{
"reportTime": "2025-02-10T23:05:56.563Z",
"cpuTemperatureInfo": [
{
"temperature": 27,
"label": "edge\n"
},
{
"temperature": 28,
"label": "Tctl\n"
},
{
"temperature": 27,
"label": "acpitz\n"
}
]
},
{
"reportTime": "2025-02-10T23:56:47.138Z",
"cpuUtilizationPercentageInfo": [28]
},
{
"reportTime": "2025-02-10T23:57:50.717Z",
"cpuTemperatureInfo": [
{
"temperature": 39,
"label": "edge\n"
},
{
"temperature": 39,
"label": "Tctl\n"
},
{
"temperature": 40,
"label": "acpitz\n"
}
]
},
{
"reportTime": "2025-02-11T07:49:44.333Z",
"cpuUtilizationPercentageInfo": [26]
},
{
"reportTime": "2025-02-11T07:50:48.473Z",
"cpuTemperatureInfo": [
{
"temperature": 26,
"label": "edge\n"
},
{
"temperature": 27,
"label": "Tctl\n"
},
{
"temperature": 27,
"label": "acpitz\n"
}
]
},
{
"reportTime": "2025-02-11T15:46:23.530Z",
"cpuUtilizationPercentageInfo": [27]
},
{
"reportTime": "2025-02-11T15:47:22.723Z",
"cpuTemperatureInfo": [
{
"temperature": 27,
"label": "edge\n"
},
{
"temperature": 28,
"label": "Tctl\n"
},
{
"temperature": 27,
"label": "acpitz\n"
}
]
},
{
"reportTime": "2025-02-11T15:52:40.368Z",
"cpuUtilizationPercentageInfo": [28]
},
{
"reportTime": "2025-02-11T15:53:41.233Z",
"cpuTemperatureInfo": [
{
"temperature": 34,
"label": "edge\n"
},
{
"temperature": 35,
"label": "Tctl\n"
},
{
"temperature": 35,
"label": "acpitz\n"
}
]
},
{
"reportTime": "2025-02-11T16:06:07.349Z",
"cpuUtilizationPercentageInfo": [30]
},
{
"reportTime": "2025-02-11T16:07:07.921Z",
"cpuTemperatureInfo": [
{
"temperature": 39,
"label": "edge\n"
},
{
"temperature": 39,
"label": "Tctl\n"
},
{
"temperature": 40,
"label": "acpitz\n"
}
]
},
{
"reportTime": "2025-02-11T16:13:28.511Z",
"cpuUtilizationPercentageInfo": [25]
},
{
"reportTime": "2025-02-11T16:14:27.628Z",
"cpuTemperatureInfo": [
{
"temperature": 36,
"label": "edge\n"
},
{
"temperature": 37,
"label": "Tctl\n"
},
{
"temperature": 37,
"label": "acpitz\n"
}
]
},
{
"reportTime": "2025-02-11T16:17:06.188Z",
"cpuUtilizationPercentageInfo": [27]
},
{
"reportTime": "2025-02-11T16:18:06.375Z",
"cpuTemperatureInfo": [
{
"temperature": 40,
"label": "edge\n"
},
{
"temperature": 41,
"label": "Tctl\n"
},
{
"temperature": 42,
"label": "acpitz\n"
}
]
},
{
"reportTime": "2025-02-11T16:36:20.232Z",
"cpuUtilizationPercentageInfo": [27]
},
{
"reportTime": "2025-02-11T16:37:20.599Z",
"cpuTemperatureInfo": [
{
"temperature": 45,
"label": "edge\n"
},
{
"temperature": 58,
"label": "Tctl\n"
},
{
"temperature": 45,
"label": "acpitz\n"
}
]
},
{
"reportTime": "2025-02-11T16:48:45.267Z",
"cpuUtilizationPercentageInfo": [27]
},
{
"reportTime": "2025-02-11T16:49:44.854Z",
"cpuTemperatureInfo": [
{
"temperature": 42,
"label": "edge\n"
},
{
"temperature": 44,
"label": "Tctl\n"
},
{
"temperature": 44,
"label": "acpitz\n"
}
]
},
{
"reportTime": "2025-02-12T06:35:29.337Z",
"cpuUtilizationPercentageInfo": [30]
},
{
"reportTime": "2025-02-12T06:36:28.433Z",
"cpuTemperatureInfo": [
{
"temperature": 42,
"label": "edge\n"
},
{
"temperature": 42,
"label": "Tctl\n"
},
{
"temperature": 42,
"label": "acpitz\n"
}
]
}
],
"systemRamTotal": "16089374720",
"systemRamFreeReports": [
{
"reportTime": "2025-02-10T17:03:13.230Z",
"systemRamFreeInfo": ["13905453056"]
},
{
"reportTime": "2025-02-10T17:11:01.697Z",
"systemRamFreeInfo": ["15221055488"]
},
{
"reportTime": "2025-02-10T17:47:32.153Z",
"systemRamFreeInfo": ["15237283840"]
},
{
"reportTime": "2025-02-10T18:56:23.878Z",
"systemRamFreeInfo": ["15228760064"]
},
{
"reportTime": "2025-02-10T23:04:56.127Z",
"systemRamFreeInfo": ["15228022784"]
},
{
"reportTime": "2025-02-10T23:56:46.839Z",
"systemRamFreeInfo": ["15226499072"]
},
{
"reportTime": "2025-02-11T07:49:43.939Z",
"systemRamFreeInfo": ["15229087744"]
},
{
"reportTime": "2025-02-11T15:46:23.165Z",
"systemRamFreeInfo": ["15226187776"]
},
{
"reportTime": "2025-02-11T15:52:39.966Z",
"systemRamFreeInfo": ["15226843136"]
},
{
"reportTime": "2025-02-11T16:06:06.871Z",
"systemRamFreeInfo": ["15225753600"]
},
{
"reportTime": "2025-02-11T16:13:28.176Z",
"systemRamFreeInfo": ["15228182528"]
},
{
"reportTime": "2025-02-11T16:17:05.936Z",
"systemRamFreeInfo": ["15223095296"]
},
{
"reportTime": "2025-02-11T16:36:19.897Z",
"systemRamFreeInfo": ["15226126336"]
},
{
"reportTime": "2025-02-11T16:48:44.934Z",
"systemRamFreeInfo": ["15226707968"]
},
{
"reportTime": "2025-02-12T06:35:28.949Z",
"systemRamFreeInfo": ["15222706176"]
}
],
"diskVolumeReports": [
{
"volumeInfo": [
{
"volumeId": "/media/archive",
"storageTotal": "8044687360",
"storageFree": "8044687360"
},
{
"volumeId": "/media/removable",
"storageTotal": "8044687360",
"storageFree": "8044687360"
}
]
}
],
"lastKnownNetwork": [
{
"ipAddress": "192.168.0.106",
"wanIpAddress": "87.121.13.137"
}
],
"cpuInfo": [
{
"model": "AMD Ryzen 5 4500U with Radeon Graphics",
"architecture": "x64",
"maxClockSpeedKhz": 2375000,
"logicalCpus": [
{
"maxScalingFrequencyKhz": 2375000,
"currentScalingFrequencyKhz": 1397253,
"idleDuration": "60s",
"cStates": [
{
"displayName": "C3",
"sessionDuration": "59.509354s"
},
{
"displayName": "C1",
"sessionDuration": "1.338153s"
},
{
"displayName": "C2",
"sessionDuration": "0.241264s"
},
{
"displayName": "POLL",
"sessionDuration": "0.004477s"
}
]
},
{
"maxScalingFrequencyKhz": 2375000,
"currentScalingFrequencyKhz": 1397372,
"idleDuration": "60s",
"cStates": [
{
"displayName": "C3",
"sessionDuration": "58.861175s"
},
{
"displayName": "C1",
"sessionDuration": "1.335068s"
},
{
"displayName": "C2",
"sessionDuration": "0.761853s"
},
{
"displayName": "POLL",
"sessionDuration": "0.007583s"
}
]
},
{
"maxScalingFrequencyKhz": 2375000,
"currentScalingFrequencyKhz": 1397454,
"idleDuration": "58s",
"cStates": [
{
"displayName": "C3",
"sessionDuration": "57.457528s"
},
{
"displayName": "C1",
"sessionDuration": "1.280076s"
},
{
"displayName": "C2",
"sessionDuration": "0.167642s"
},
{
"displayName": "POLL",
"sessionDuration": "0.003444s"
}
]
},
{
"maxScalingFrequencyKhz": 2375000,
"currentScalingFrequencyKhz": 1397348,
"idleDuration": "59s",
"cStates": [
{
"displayName": "C3",
"sessionDuration": "58.906343s"
},
{
"displayName": "C1",
"sessionDuration": "1.101873s"
},
{
"displayName": "C2",
"sessionDuration": "0.119013s"
},
{
"displayName": "POLL",
"sessionDuration": "0.009095s"
}
]
},
{
"maxScalingFrequencyKhz": 2375000,
"currentScalingFrequencyKhz": 1383188,
"idleDuration": "60s",
"cStates": [
{
"displayName": "C3",
"sessionDuration": "59.476621s"
},
{
"displayName": "C1",
"sessionDuration": "1.048691s"
},
{
"displayName": "C2",
"sessionDuration": "0.192808s"
},
{
"displayName": "POLL",
"sessionDuration": "0.003546s"
}
]
},
{
"maxScalingFrequencyKhz": 2375000,
"currentScalingFrequencyKhz": 1397437,
"idleDuration": "60s",
"cStates": [
{
"displayName": "C3",
"sessionDuration": "60.155800s"
},
{
"displayName": "C1",
"sessionDuration": "0.681644s"
},
{
"displayName": "C2",
"sessionDuration": "0.143131s"
},
{
"displayName": "POLL",
"sessionDuration": "0.004276s"
}
]
}
]
}
],
"extendedSupportEligible": false,
"chromeOsType": "chromeOsFlex",
"diskSpaceUsage": {
"capacityBytes": "549755813888",
"usedBytes": "85613068288"
}
}
}
]
}
}
@@ -0,0 +1,27 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import nock from 'nock';
describe('Google GSuiteAdmin Node - Create Group', () => {
beforeEach(() => {
nock.disableNetConnect();
nock('https://www.googleapis.com/admin')
.post('/directory/v1/groups', {
email: 'NewOnes22@example.com',
name: 'Test',
description: 'test',
})
.reply(200, {
kind: 'admin#directory#group',
id: '03mzq4wv15cepg2',
etag: '"example"',
email: 'NewOnes22@example.com',
name: 'Test',
description: 'test',
adminCreated: true,
});
});
new NodeTestHarness().setupTests({
workflowFiles: ['create.workflow.json'],
});
});
@@ -0,0 +1,61 @@
{
"nodes": [
{
"parameters": {},
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [120, 700],
"id": "0e76b314-4994-4141-975f-9614c6094c80",
"name": "When clicking Execute workflow"
},
{
"parameters": {
"resource": "group",
"name": "Test",
"email": "NewOnes22@example.com",
"additionalFields": {
"description": "test"
}
},
"type": "n8n-nodes-base.gSuiteAdmin",
"typeVersion": 1,
"position": [60, 1140],
"id": "54a9e564-bff5-4d86-b684-e5cf5b34b48c",
"name": "Create Group",
"credentials": {
"gSuiteAdminOAuth2Api": {
"id": "OXfPMaggXFJ0RLkw",
"name": "Google Workspace Admin account"
}
}
}
],
"connections": {
"When clicking Execute workflow": {
"main": [
[
{
"node": "Create Group",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Create Group": [
{
"json": {
"kind": "admin#directory#group",
"id": "03mzq4wv15cepg2",
"etag": "\"example\"",
"email": "NewOnes22@example.com",
"name": "Test",
"description": "test",
"adminCreated": true
}
}
]
}
}
@@ -0,0 +1,15 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import nock from 'nock';
describe('Google GSuiteAdmin Node - Delete Group', () => {
beforeEach(() => {
nock.disableNetConnect();
nock('https://www.googleapis.com/admin')
.delete('/directory/v1/groups/01302m922pmp3e4')
.reply(204, '');
});
new NodeTestHarness().setupTests({
workflowFiles: ['delete.workflow.json'],
});
});
@@ -0,0 +1,55 @@
{
"nodes": [
{
"parameters": {},
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [120, 700],
"id": "0e76b314-4994-4141-975f-9614c6094c80",
"name": "When clicking Execute workflow"
},
{
"parameters": {
"resource": "group",
"operation": "delete",
"groupId": {
"__rl": true,
"value": "01302m922pmp3e4",
"mode": "list",
"cachedResultName": "new2"
}
},
"type": "n8n-nodes-base.gSuiteAdmin",
"typeVersion": 1,
"position": [60, 1140],
"id": "9d6f8739-8a1b-4b85-9e5c-84a184e6dbaf",
"name": "Delete Group",
"credentials": {
"gSuiteAdminOAuth2Api": {
"id": "OXfPMaggXFJ0RLkw",
"name": "Google Workspace Admin account"
}
}
}
],
"connections": {
"When clicking Execute workflow": {
"main": [
[
{
"node": "Delete Group",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Delete Group": [
{
"json": { "success": true }
}
]
}
}
@@ -0,0 +1,31 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import nock from 'nock';
describe('Google GSuiteAdmin Node - Get Group', () => {
beforeEach(() => {
nock.disableNetConnect();
nock('https://www.googleapis.com/admin')
.get('/directory/v1/groups/01302m922pmp3e4')
.reply(200, {
kind: 'admin#directory#group',
id: '01302m922pmp3e4',
etag: '"example"',
email: 'new3@example.com',
name: 'new2',
directMembersCount: '2',
description: 'new1',
adminCreated: true,
aliases: ['new2@example.com', 'new@example.com', 'NewOnes@example.com'],
nonEditableAliases: [
'NewOnes@example.com.test-google-a.com',
'new@example.com.test-google-a.com',
'new2@example.com.test-google-a.com',
'new3@example.com.test-google-a.com',
],
});
});
new NodeTestHarness().setupTests({
workflowFiles: ['get.workflow.json'],
});
});
@@ -0,0 +1,71 @@
{
"nodes": [
{
"parameters": {},
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [120, 700],
"id": "0e76b314-4994-4141-975f-9614c6094c80",
"name": "When clicking Execute workflow"
},
{
"parameters": {
"resource": "group",
"operation": "get",
"groupId": {
"__rl": true,
"value": "01302m922pmp3e4",
"mode": "list",
"cachedResultName": "new2"
}
},
"type": "n8n-nodes-base.gSuiteAdmin",
"typeVersion": 1,
"position": [80, 1120],
"id": "8d47d64b-80df-479a-8e1d-d63991f5d23b",
"name": "Get Group",
"credentials": {
"gSuiteAdminOAuth2Api": {
"id": "OXfPMaggXFJ0RLkw",
"name": "Google Workspace Admin account"
}
}
}
],
"connections": {
"When clicking Execute workflow": {
"main": [
[
{
"node": "Get Group",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Get Group": [
{
"json": {
"kind": "admin#directory#group",
"id": "01302m922pmp3e4",
"etag": "\"example\"",
"email": "new3@example.com",
"name": "new2",
"directMembersCount": "2",
"description": "new1",
"adminCreated": true,
"aliases": ["new2@example.com", "new@example.com", "NewOnes@example.com"],
"nonEditableAliases": [
"NewOnes@example.com.test-google-a.com",
"new@example.com.test-google-a.com",
"new2@example.com.test-google-a.com",
"new3@example.com.test-google-a.com"
]
}
}
]
}
}
@@ -0,0 +1,46 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import nock from 'nock';
describe('Google GSuiteAdmin Node - Get All Groups', () => {
beforeEach(() => {
nock.disableNetConnect();
nock('https://www.googleapis.com/admin')
.get('/directory/v1/groups')
.query({
customer: 'my_customer',
maxResults: '100',
})
.reply(200, {
kind: 'admin#directory#groups',
etag: '"test_etag"',
groups: [
{
kind: 'admin#directory#group',
id: '01x0gk373c9z46j',
etag: '"example"',
email: 'newoness@example.com',
name: 'NewOness',
directMembersCount: '1',
description: 'test',
adminCreated: true,
nonEditableAliases: ['NewOness@example.com.test-google-a.com'],
},
{
kind: 'admin#directory#group',
id: '01tuee742txc3k4',
etag: '"example"',
email: 'newonesss@example.com',
name: 'NewOne3',
directMembersCount: '0',
description: 'test',
adminCreated: true,
nonEditableAliases: ['NewOnesss@example.com.test-google-a.com'],
},
],
});
});
new NodeTestHarness().setupTests({
workflowFiles: ['getAll.workflow.json'],
});
});
@@ -0,0 +1,74 @@
{
"nodes": [
{
"parameters": {},
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [120, 700],
"id": "0e76b314-4994-4141-975f-9614c6094c80",
"name": "When clicking Execute workflow"
},
{
"parameters": {
"resource": "group",
"operation": "getAll",
"returnAll": true,
"filter": {}
},
"type": "n8n-nodes-base.gSuiteAdmin",
"typeVersion": 1,
"position": [100, 1120],
"id": "30263040-3578-4ce6-b19c-f665b85ca301",
"name": "Get Many",
"credentials": {
"gSuiteAdminOAuth2Api": {
"id": "OXfPMaggXFJ0RLkw",
"name": "Google Workspace Admin account"
}
}
}
],
"connections": {
"When clicking Execute workflow": {
"main": [
[
{
"node": "Get Many",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Get Many": [
{
"json": {
"kind": "admin#directory#group",
"id": "01x0gk373c9z46j",
"etag": "\"example\"",
"email": "newoness@example.com",
"name": "NewOness",
"directMembersCount": "1",
"description": "test",
"adminCreated": true,
"nonEditableAliases": ["NewOness@example.com.test-google-a.com"]
}
},
{
"json": {
"kind": "admin#directory#group",
"id": "01tuee742txc3k4",
"etag": "\"example\"",
"email": "newonesss@example.com",
"name": "NewOne3",
"directMembersCount": "0",
"description": "test",
"adminCreated": true,
"nonEditableAliases": ["NewOnesss@example.com.test-google-a.com"]
}
}
]
}
}
@@ -0,0 +1,28 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import nock from 'nock';
describe('Google GSuiteAdmin Node - Update Group', () => {
beforeEach(() => {
nock.disableNetConnect();
nock('https://www.googleapis.com/admin')
.put('/directory/v1/groups/01302m922p525286')
.reply(200, {
kind: 'admin#directory#group',
id: '01302m922p525286',
etag: '"example"',
email: 'new3@example.com',
name: 'new2',
description: 'new1',
adminCreated: true,
aliases: ['new@example.com', 'NewOnes@example.com', 'new2@example.com'],
nonEditableAliases: [
'NewOnes@example.com.test-google-a.com',
'new@example.com.test-google-a.com',
],
});
});
new NodeTestHarness().setupTests({
workflowFiles: ['update.workflow.json'],
});
});
@@ -0,0 +1,73 @@
{
"nodes": [
{
"parameters": {},
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [120, 700],
"id": "0e76b314-4994-4141-975f-9614c6094c80",
"name": "When clicking Execute workflow"
},
{
"parameters": {
"resource": "group",
"operation": "update",
"groupId": {
"__rl": true,
"value": "01302m922p525286",
"mode": "list",
"cachedResultName": "new"
},
"updateFields": {
"description": "new1",
"email": "new3@example.com",
"name": "new2"
}
},
"type": "n8n-nodes-base.gSuiteAdmin",
"typeVersion": 1,
"position": [80, 1100],
"id": "013eec82-8d52-4485-88eb-d9caf112d539",
"name": "Update Group",
"credentials": {
"gSuiteAdminOAuth2Api": {
"id": "OXfPMaggXFJ0RLkw",
"name": "Google Workspace Admin account"
}
}
}
],
"connections": {
"When clicking Execute workflow": {
"main": [
[
{
"node": "Update Group",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Update Group": [
{
"json": {
"kind": "admin#directory#group",
"id": "01302m922p525286",
"etag": "\"example\"",
"email": "new3@example.com",
"name": "new2",
"description": "new1",
"adminCreated": true,
"aliases": ["new@example.com", "NewOnes@example.com", "new2@example.com"],
"nonEditableAliases": [
"NewOnes@example.com.test-google-a.com",
"new@example.com.test-google-a.com"
]
}
}
]
}
}
@@ -0,0 +1,25 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import nock from 'nock';
describe('Google GSuiteAdmin Node - Add User to Group', () => {
beforeEach(() => {
nock.disableNetConnect();
nock('https://www.googleapis.com/admin')
.get('/directory/v1/users/114393134535981252528')
.reply(200, { primaryEmail: 'newone@example.com' });
nock('https://www.googleapis.com/admin')
.post('/directory/v1/groups/01302m922pmp3e4/members', {
email: 'newone@example.com',
role: 'MEMBER',
})
.reply(200, {
kind: 'admin#directory#member',
status: 'ACTIVE',
});
});
new NodeTestHarness().setupTests({
workflowFiles: ['addToGroup.workflow.json'],
});
});
@@ -0,0 +1,60 @@
{
"nodes": [
{
"parameters": {},
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [120, 700],
"id": "0e76b314-4994-4141-975f-9614c6094c80",
"name": "When clicking Execute workflow"
},
{
"parameters": {
"operation": "addToGroup",
"userId": {
"__rl": true,
"value": "114393134535981252528",
"mode": "list",
"cachedResultName": "NewOne User"
},
"groupId": {
"__rl": true,
"value": "01302m922pmp3e4",
"mode": "list",
"cachedResultName": "new"
}
},
"type": "n8n-nodes-base.gSuiteAdmin",
"typeVersion": 1,
"position": [80, 1100],
"id": "b0c8042f-4ce1-41f1-9d14-876d5cac3ccf",
"name": "Add To Group",
"credentials": {
"gSuiteAdminOAuth2Api": {
"id": "OXfPMaggXFJ0RLkw",
"name": "Google Workspace Admin account"
}
}
}
],
"connections": {
"When clicking Execute workflow": {
"main": [
[
{
"node": "Add To Group",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Add To Group": [
{
"json": { "added": true }
}
]
}
}
@@ -0,0 +1,44 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import nock from 'nock';
describe('Google GSuiteAdmin Node - Create User', () => {
beforeEach(() => {
nock.disableNetConnect();
nock('https://www.googleapis.com/admin')
.post('/directory/v1/users')
.reply(200, {
kind: 'admin#directory#user',
id: '112507770188715525288',
etag: '"example"',
primaryEmail: 'new@example.com',
name: {
givenName: 'NewOne',
familyName: 'User',
},
emails: [
{
address: 'test@mail.com',
type: 'work',
},
],
phones: [
{
primary: false,
type: 'work',
value: '+1-202-555-0123',
},
],
isAdmin: false,
isDelegatedAdmin: false,
creationTime: '2024-12-20T20:48:53.000Z',
customerId: 'C4444hnz2',
orgUnitPath: '/',
isMailboxSetup: false,
});
});
new NodeTestHarness().setupTests({
workflowFiles: ['create.workflow.json'],
});
});
@@ -0,0 +1,107 @@
{
"nodes": [
{
"parameters": {},
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [120, 700],
"id": "0e76b314-4994-4141-975f-9614c6094c80",
"name": "When clicking Execute workflow"
},
{
"parameters": {
"firstName": "NewOne",
"lastName": "User",
"password": "12345678",
"username": "new",
"domain": "example.com",
"additionalFields": {
"changePasswordAtNextLogin": true,
"phoneUi": {
"phoneValues": [
{
"value": "+1-202-555-0123"
}
]
},
"emailUi": {
"emailValues": [
{
"address": "test@mail.com"
}
]
},
"roles": ["groupsAdmin"],
"customFields": {
"fieldValues": [
{
"schemaName": "NewTest",
"fieldName": "test",
"value": "test"
}
]
}
}
},
"type": "n8n-nodes-base.gSuiteAdmin",
"typeVersion": 1,
"position": [100, 1100],
"id": "54227da8-70ad-456a-8d75-f7e28d514e90",
"name": "Create User",
"credentials": {
"gSuiteAdminOAuth2Api": {
"id": "OXfPMaggXFJ0RLkw",
"name": "Google Workspace Admin account"
}
}
}
],
"connections": {
"When clicking Execute workflow": {
"main": [
[
{
"node": "Create User",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Create User": [
{
"json": {
"kind": "admin#directory#user",
"id": "112507770188715525288",
"etag": "\"example\"",
"primaryEmail": "new@example.com",
"name": {
"givenName": "NewOne",
"familyName": "User"
},
"isAdmin": false,
"isDelegatedAdmin": false,
"creationTime": "2024-12-20T20:48:53.000Z",
"emails": [
{
"address": "test@mail.com",
"type": "work"
}
],
"phones": [
{
"value": "+1-202-555-0123",
"primary": false,
"type": "work"
}
],
"customerId": "C4444hnz2",
"orgUnitPath": "/",
"isMailboxSetup": false
}
}
]
}
}
@@ -0,0 +1,16 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import nock from 'nock';
describe('Google GSuiteAdmin Node - Delete User', () => {
beforeEach(() => {
nock.disableNetConnect();
nock('https://www.googleapis.com/admin')
.delete('/directory/v1/users/114393134535981252212')
.reply(200, {});
});
new NodeTestHarness().setupTests({
workflowFiles: ['delete.workflow.json'],
});
});
@@ -0,0 +1,56 @@
{
"nodes": [
{
"parameters": {},
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [120, 700],
"id": "0e76b314-4994-4141-975f-9614c6094c80",
"name": "When clicking Execute workflow"
},
{
"parameters": {
"operation": "delete",
"userId": {
"__rl": true,
"value": "114393134535981252212",
"mode": "list",
"cachedResultName": "NewOne22 User22"
}
},
"type": "n8n-nodes-base.gSuiteAdmin",
"typeVersion": 1,
"position": [120, 1100],
"id": "39f9a9c0-2ea5-45b2-a346-55017dfa4e43",
"name": "Delete User",
"credentials": {
"gSuiteAdminOAuth2Api": {
"id": "OXfPMaggXFJ0RLkw",
"name": "Google Workspace Admin account"
}
}
}
],
"connections": {
"When clicking Execute workflow": {
"main": [
[
{
"node": "Delete User",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Delete User": [
{
"json": {
"deleted": true
}
}
]
}
}
@@ -0,0 +1,36 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import nock from 'nock';
describe('Google GSuiteAdmin Node - Get User', () => {
beforeEach(() => {
nock.disableNetConnect();
nock('https://www.googleapis.com/admin')
.get('/directory/v1/users/112507770188715252026')
.query({ projection: 'basic' })
.reply(200, {
kind: 'admin#directory#user',
id: '112507770188715252026',
primaryEmail: 'new@example.com',
name: {
givenName: 'New One',
familyName: 'User',
fullName: 'New One User',
},
isAdmin: false,
lastLoginTime: '1970-01-01T00:00:00.000Z',
creationTime: '2024-12-20T20:48:53.000Z',
suspended: true,
emails: [
{
address: 'new@example.com',
primary: true,
},
],
});
});
new NodeTestHarness().setupTests({
workflowFiles: ['get.workflow.json'],
});
});
@@ -0,0 +1,67 @@
{
"nodes": [
{
"parameters": {},
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [120, 700],
"id": "0e76b314-4994-4141-975f-9614c6094c80",
"name": "When clicking Execute workflow"
},
{
"parameters": {
"operation": "get",
"userId": {
"__rl": true,
"value": "112507770188715252026",
"mode": "list",
"cachedResultName": "NewOne22 User22"
}
},
"type": "n8n-nodes-base.gSuiteAdmin",
"typeVersion": 1,
"position": [120, 1100],
"id": "b39d3a72-6e81-4219-82eb-f39d99eace16",
"name": "Get User",
"credentials": {
"gSuiteAdminOAuth2Api": {
"id": "OXfPMaggXFJ0RLkw",
"name": "Google Workspace Admin account"
}
}
}
],
"connections": {
"When clicking Execute workflow": {
"main": [
[
{
"node": "Get User",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Get User": [
{
"json": {
"kind": "admin#directory#user",
"id": "112507770188715252026",
"primaryEmail": "new@example.com",
"name": {
"givenName": "New One",
"familyName": "User",
"fullName": "New One User"
},
"isAdmin": false,
"lastLoginTime": "1970-01-01T00:00:00.000Z",
"creationTime": "2024-12-20T20:48:53.000Z",
"suspended": true
}
}
]
}
}
@@ -0,0 +1,65 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import nock from 'nock';
describe('Google GSuiteAdmin Node - Get All Users', () => {
beforeEach(() => {
nock.disableNetConnect();
nock('https://www.googleapis.com/admin')
.get('/directory/v1/users')
.query({
projection: 'basic',
customer: 'my_customer',
maxResults: '100',
})
.reply(200, {
kind: 'admin#directory#users',
users: [
{
kind: 'admin#directory#user',
id: '112507770188715252055',
primaryEmail: 'new@example.com',
name: {
givenName: 'New',
familyName: 'User',
fullName: 'New User',
},
isAdmin: false,
lastLoginTime: '1970-01-01T00:00:00.000Z',
creationTime: '2024-12-20T20:48:53.000Z',
suspended: true,
emails: [
{
address: 'new@example.com',
primary: true,
},
],
},
{
kind: 'admin#directory#user',
id: '222459372679230452528',
primaryEmail: 'test33@example.com',
name: {
givenName: 'New',
familyName: 'Test',
fullName: 'New Test',
},
isAdmin: true,
lastLoginTime: '2024-12-19T08:39:56.000Z',
creationTime: '2024-09-06T11:48:38.000Z',
suspended: false,
emails: [
{
address: 'test33@example.com',
primary: true,
},
],
},
],
});
});
new NodeTestHarness().setupTests({
workflowFiles: ['getAll.workflow.json'],
});
});
@@ -0,0 +1,78 @@
{
"nodes": [
{
"parameters": {},
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [120, 700],
"id": "0e76b314-4994-4141-975f-9614c6094c80",
"name": "When clicking Execute workflow"
},
{
"parameters": {
"operation": "getAll",
"filter": {}
},
"type": "n8n-nodes-base.gSuiteAdmin",
"typeVersion": 1,
"position": [140, 1100],
"id": "4107ee9d-37e1-4d85-9099-25ec13211ee1",
"name": "Get Many",
"credentials": {
"gSuiteAdminOAuth2Api": {
"id": "OXfPMaggXFJ0RLkw",
"name": "Google Workspace Admin account"
}
}
}
],
"connections": {
"When clicking Execute workflow": {
"main": [
[
{
"node": "Get Many",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Get Many": [
{
"json": {
"kind": "admin#directory#user",
"id": "112507770188715252055",
"primaryEmail": "new@example.com",
"name": {
"givenName": "New",
"familyName": "User",
"fullName": "New User"
},
"isAdmin": false,
"lastLoginTime": "1970-01-01T00:00:00.000Z",
"creationTime": "2024-12-20T20:48:53.000Z",
"suspended": true
}
},
{
"json": {
"kind": "admin#directory#user",
"id": "222459372679230452528",
"primaryEmail": "test33@example.com",
"name": {
"givenName": "New",
"familyName": "Test",
"fullName": "New Test"
},
"isAdmin": true,
"lastLoginTime": "2024-12-19T08:39:56.000Z",
"creationTime": "2024-09-06T11:48:38.000Z",
"suspended": false
}
}
]
}
}
@@ -0,0 +1,16 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import nock from 'nock';
describe('Google GSuiteAdmin Node - Remove User from Group', () => {
beforeEach(() => {
nock.disableNetConnect();
nock('https://www.googleapis.com/admin')
.delete('/directory/v1/groups/01302m922pmp3e4/members/114393134535981252528')
.reply(200, {});
});
new NodeTestHarness().setupTests({
workflowFiles: ['removeFromGroup.workflow.json'],
});
});
@@ -0,0 +1,60 @@
{
"nodes": [
{
"parameters": {},
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [120, 700],
"id": "0e76b314-4994-4141-975f-9614c6094c80",
"name": "When clicking Execute workflow"
},
{
"parameters": {
"operation": "removeFromGroup",
"userId": {
"__rl": true,
"value": "114393134535981252528",
"mode": "list",
"cachedResultName": "New User"
},
"groupId": {
"__rl": true,
"value": "01302m922pmp3e4",
"mode": "list",
"cachedResultName": "new2"
}
},
"type": "n8n-nodes-base.gSuiteAdmin",
"typeVersion": 1,
"position": [140, 1100],
"id": "9a323b95-1495-487f-ba27-2df737bd5bdf",
"name": "Remove From Group",
"credentials": {
"gSuiteAdminOAuth2Api": {
"id": "OXfPMaggXFJ0RLkw",
"name": "Google Workspace Admin account"
}
}
}
],
"connections": {
"When clicking Execute workflow": {
"main": [
[
{
"node": "Remove From Group",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Remove From Group": [
{
"json": { "removed": true }
}
]
}
}
@@ -0,0 +1,75 @@
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import nock from 'nock';
describe('Google GSuiteAdmin Node - Update User', () => {
beforeEach(() => {
nock.disableNetConnect();
nock('https://www.googleapis.com/admin')
.put('/directory/v1/users/101071249467630629404', {
name: {
givenName: 'test',
familyName: 'new',
},
primaryEmail: 'one@example.com',
phones: [
{
type: 'assistant',
value: '123',
primary: true,
},
],
emails: [
{
address: 'newone@example.com',
type: 'home',
},
],
})
.reply(200, {
kind: 'admin#directory#user',
id: '101071249467630629404',
etag: '"example"',
primaryEmail: 'one@example.com',
name: {
givenName: 'test',
familyName: 'new',
},
isAdmin: false,
isDelegatedAdmin: false,
lastLoginTime: '1970-01-01T00:00:00.000Z',
creationTime: '2025-03-26T21:28:53.000Z',
agreedToTerms: false,
suspended: false,
archived: false,
changePasswordAtNextLogin: false,
ipWhitelisted: false,
emails: [
{
address: 'newone@example.com',
type: 'home',
},
],
phones: [
{
value: '123',
primary: true,
type: 'assistant',
},
],
aliases: ['new22@example.com'],
nonEditableAliases: ['new22@example.com.test-google-a.com'],
customerId: 'C0442hnz1',
orgUnitPath: '/',
isMailboxSetup: false,
includeInGlobalAddressList: true,
thumbnailPhotoUrl: '//example',
thumbnailPhotoEtag: '"example"',
recoveryEmail: '',
});
});
new NodeTestHarness().setupTests({
workflowFiles: ['update.workflow.json'],
});
});
@@ -0,0 +1,117 @@
{
"nodes": [
{
"parameters": {},
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [120, 700],
"id": "0e76b314-4994-4141-975f-9614c6094c80",
"name": "When clicking Execute workflow"
},
{
"parameters": {
"operation": "update",
"userId": {
"__rl": true,
"value": "101071249467630629404",
"mode": "list",
"cachedResultName": "NewOne22 User22"
},
"updateFields": {
"archived": true,
"firstName": "test",
"lastName": "new",
"phoneUi": {
"phoneValues": [
{
"type": "assistant",
"value": "123",
"primary": true
}
]
},
"primaryEmail": "one@example.com",
"emailUi": {
"emailValues": [
{
"type": "home",
"address": "newone@example.com"
}
]
}
}
},
"type": "n8n-nodes-base.gSuiteAdmin",
"typeVersion": 1,
"position": [140, 1100],
"id": "b4cd1391-cfdc-4f36-8c2f-f18a9ad4f795",
"name": "Update User",
"credentials": {
"gSuiteAdminOAuth2Api": {
"id": "OXfPMaggXFJ0RLkw",
"name": "Google Workspace Admin account"
}
}
}
],
"connections": {
"When clicking Execute workflow": {
"main": [
[
{
"node": "Update User",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Update User": [
{
"json": {
"kind": "admin#directory#user",
"id": "101071249467630629404",
"etag": "\"example\"",
"primaryEmail": "one@example.com",
"name": {
"givenName": "test",
"familyName": "new"
},
"isAdmin": false,
"isDelegatedAdmin": false,
"lastLoginTime": "1970-01-01T00:00:00.000Z",
"creationTime": "2025-03-26T21:28:53.000Z",
"agreedToTerms": false,
"suspended": false,
"archived": false,
"changePasswordAtNextLogin": false,
"ipWhitelisted": false,
"emails": [
{
"address": "newone@example.com",
"type": "home"
}
],
"phones": [
{
"value": "123",
"primary": true,
"type": "assistant"
}
],
"aliases": ["new22@example.com"],
"nonEditableAliases": ["new22@example.com.test-google-a.com"],
"customerId": "C0442hnz1",
"orgUnitPath": "/",
"isMailboxSetup": false,
"includeInGlobalAddressList": true,
"thumbnailPhotoUrl": "//example",
"thumbnailPhotoEtag": "\"example\"",
"recoveryEmail": ""
}
}
]
}
}