Files
alighasami 3d5eaf9445
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
first commit
2026-03-17 16:22:57 +03:30

438 lines
11 KiB
TypeScript

import { NodeTestHarness } from '@nodes-testing/node-test-harness';
import { jsonParse } from 'n8n-workflow';
import nock from 'nock';
describe('Google Contacts', () => {
const credentials = {
googleContactsOAuth2Api: {
scope: 'https://www.googleapis.com/auth/contacts',
oauthTokenData: {
access_token: 'test-access-token',
},
},
};
describe('Contact Create Operation', () => {
beforeAll(() => {
const mock = nock('https://people.googleapis.com/v1');
// Mock successful contact creation - handle all variations
mock
.post('/people:createContact')
.reply(function (_, requestBody: any) {
const parsedBody = typeof requestBody === 'string' ? jsonParse(requestBody) : requestBody;
if (parsedBody.names && parsedBody.names[0].givenName === 'John') {
return [
201,
{
resourceName: 'people/c123456789',
etag: '%EgYBAgMEBQYHCCESBCAFIAI=.',
names: [
{
metadata: {
primary: true,
source: { type: 'CONTACT', id: 'c123456789' },
},
displayName: 'John Doe',
familyName: 'Doe',
givenName: 'John',
displayNameLastFirst: 'Doe, John',
},
],
},
];
}
// For any other create request (Jane or any other contact)
return [
201,
{
resourceName: 'people/c987654321',
etag: '%EgYBAgMEBQYHCCESBCAFIAI=.',
names: [
{
metadata: {
primary: true,
source: { type: 'CONTACT', id: 'c987654321' },
},
displayName: 'Dr. Jane Marie Smith Jr.',
familyName: 'Smith',
givenName: 'Jane',
middleName: 'Marie',
honorificPrefix: 'Dr.',
honorificSuffix: 'Jr.',
},
],
emailAddresses: [
{
metadata: { primary: true, source: { type: 'CONTACT', id: 'c987654321' } },
value: 'jane@example.com',
type: 'work',
},
],
phoneNumbers: [
{
metadata: { primary: true, source: { type: 'CONTACT', id: 'c987654321' } },
value: '+1234567890',
type: 'mobile',
},
],
},
];
})
.persist();
});
new NodeTestHarness().setupTests({
credentials,
workflowFiles: ['contact-create-basic.workflow.json', 'contact-create-full.workflow.json'],
});
});
describe('Contact Delete Operation', () => {
beforeAll(() => {
const mock = nock('https://people.googleapis.com/v1');
// Mock successful contact deletion
mock.delete('/people/c123456789:deleteContact').reply(200, {});
});
new NodeTestHarness().setupTests({
credentials,
workflowFiles: ['contact-delete.workflow.json'],
});
});
describe('Contact Get Operation', () => {
beforeAll(() => {
const mock = nock('https://people.googleapis.com/v1');
// Mock get contact with specific fields
mock
.get('/people/c123456789')
.query({
personFields: 'names,emailAddresses,phoneNumbers',
})
.reply(200, {
resourceName: 'people/c123456789',
etag: '%EgYBAgMEBQYHCCESBCAFIAI=.',
names: [
{
metadata: {
primary: true,
source: { type: 'CONTACT', id: 'c123456789' },
},
displayName: 'John Doe',
familyName: 'Doe',
givenName: 'John',
},
],
emailAddresses: [
{
metadata: { primary: true, source: { type: 'CONTACT', id: 'c123456789' } },
value: 'john@example.com',
type: 'work',
},
],
phoneNumbers: [
{
metadata: { primary: true, source: { type: 'CONTACT', id: 'c123456789' } },
value: '+1234567890',
type: 'mobile',
},
],
});
// Mock get contact with all fields
mock
.get('/people/c123456789')
.query({
personFields:
'addresses,biographies,birthdays,coverPhotos,emailAddresses,events,genders,imClients,interests,locales,memberships,metadata,names,nicknames,occupations,organizations,phoneNumbers,photos,relations,residences,sipAddresses,skills,urls,userDefined',
})
.reply(200, {
resourceName: 'people/c123456789',
etag: '%EgYBAgMEBQYHCCESBCAFIAI=.',
names: [
{
metadata: {
primary: true,
source: { type: 'CONTACT', id: 'c123456789' },
},
displayName: 'John Doe',
familyName: 'Doe',
givenName: 'John',
},
],
emailAddresses: [
{
metadata: { primary: true, source: { type: 'CONTACT', id: 'c123456789' } },
value: 'john@example.com',
type: 'work',
},
],
phoneNumbers: [
{
metadata: { primary: true, source: { type: 'CONTACT', id: 'c123456789' } },
value: '+1234567890',
type: 'mobile',
},
],
addresses: [
{
metadata: { primary: true, source: { type: 'CONTACT', id: 'c123456789' } },
type: 'home',
formattedValue: '123 Main St\nAnytown, CA 12345',
streetAddress: '123 Main St',
city: 'Anytown',
region: 'CA',
postalCode: '12345',
},
],
organizations: [
{
metadata: { primary: true, source: { type: 'CONTACT', id: 'c123456789' } },
name: 'Example Corp',
title: 'Software Engineer',
current: true,
},
],
});
});
new NodeTestHarness().setupTests({
credentials,
workflowFiles: ['contact-get-fields.workflow.json', 'contact-get-all.workflow.json'],
});
});
describe('Contact Get All Operation', () => {
beforeAll(() => {
const mock = nock('https://people.googleapis.com/v1');
// Mock cache warmup requests with specific empty query
mock
.get('/people:searchContacts')
.query((actualQuery) => actualQuery.query === '')
.reply(200, {
results: [],
})
.persist();
mock
.get('/people/me/connections')
.query(true) // Match any query parameters
.reply(function (uri) {
const url = new URL(uri, 'https://people.googleapis.com');
const params = url.searchParams;
// Handle different scenarios based on query params
if (params.get('pageSize') === '1') {
// Limited results case
return [
200,
{
connections: [
{
resourceName: 'people/c123456789',
etag: '%EgYBAgMEBQYHCCESBCAFIAI=.',
names: [
{
metadata: {
primary: true,
source: { type: 'CONTACT', id: 'c123456789' },
},
displayName: 'John Doe',
familyName: 'Doe',
givenName: 'John',
},
],
},
],
nextPageToken: '',
},
];
} else if (params.get('personFields') === 'names,emailAddresses') {
// Full results case with email addresses
return [
200,
{
connections: [
{
resourceName: 'people/c123456789',
etag: '%EgYBAgMEBQYHCCESBCAFIAI=.',
names: [
{
metadata: {
primary: true,
source: { type: 'CONTACT', id: 'c123456789' },
},
displayName: 'John Doe',
familyName: 'Doe',
givenName: 'John',
},
],
emailAddresses: [
{
metadata: { primary: true, source: { type: 'CONTACT', id: 'c123456789' } },
value: 'john@example.com',
type: 'work',
},
],
},
{
resourceName: 'people/c987654321',
etag: '%EgYBAgMEBQYHCCESBCAFIAI=.',
names: [
{
metadata: {
primary: true,
source: { type: 'CONTACT', id: 'c987654321' },
},
displayName: 'Jane Smith',
familyName: 'Smith',
givenName: 'Jane',
},
],
emailAddresses: [
{
metadata: { primary: true, source: { type: 'CONTACT', id: 'c987654321' } },
value: 'jane@example.com',
type: 'work',
},
],
},
],
nextPageToken: '',
},
];
}
// Default response for cache warmup and other requests
return [200, { connections: [] }];
})
.persist();
// Mock search contacts using query with function to better handle
mock
.get('/people:searchContacts')
.query(true)
.reply(function (uri) {
const url = new URL(uri, 'https://people.googleapis.com');
const params = url.searchParams;
// Handle search query specifically
if (params.get('query') === 'John' && params.get('readMask')) {
return [
200,
{
results: [
{
person: {
resourceName: 'people/c123456789',
etag: '%EgYBAgMEBQYHCCESBCAFIAI=.',
names: [
{
metadata: {
primary: true,
source: { type: 'CONTACT', id: 'c123456789' },
},
displayName: 'John Doe',
familyName: 'Doe',
givenName: 'John',
},
],
emailAddresses: [
{
metadata: {
primary: true,
source: { type: 'CONTACT', id: 'c123456789' },
},
value: 'john@example.com',
type: 'work',
},
],
},
},
],
nextPageToken: '',
},
];
}
// Default response for cache warmup
return [200, { results: [] }];
})
.persist();
});
new NodeTestHarness().setupTests({
credentials,
workflowFiles: [
'contact-getall-connections.workflow.json',
'contact-getall-search.workflow.json',
'contact-getall-limit.workflow.json',
],
});
});
describe('Contact Update Operation', () => {
beforeAll(() => {
const mock = nock('https://people.googleapis.com/v1');
// Mock etag fetch for update
mock
.get('/people/c123456789')
.query({
personFields: 'Names',
})
.reply(200, {
resourceName: 'people/c123456789',
etag: '%EgYBAgMEBQYHCCESBCAFIAI=.',
names: [
{
metadata: {
primary: true,
source: { type: 'CONTACT', id: 'c123456789' },
},
displayName: 'John Doe',
familyName: 'Doe',
givenName: 'John',
},
],
});
// Mock contact update with more flexible query matching
mock
.patch('/people/c123456789:updateContact')
.query(true) // Match any query parameters
.reply(200, {
resourceName: 'people/c123456789',
etag: '%EgYBAgMEBQYHCCESBCAFIAI=.',
names: [
{
metadata: {
primary: true,
source: { type: 'CONTACT', id: 'c123456789' },
},
displayName: 'John Updated Doe',
familyName: 'Doe',
givenName: 'John Updated',
},
],
emailAddresses: [
{
metadata: { primary: true, source: { type: 'CONTACT', id: 'c123456789' } },
value: 'john.updated@example.com',
type: 'work',
},
],
});
});
new NodeTestHarness().setupTests({
credentials,
workflowFiles: ['contact-update.workflow.json'],
});
});
});