Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -657,10 +657,10 @@ const sequences = await analytics.V1.Sequences.getSequences({ page: 1 });

#### createSequenceEmail

Wraps [`POST /v1/fetch/sequences/:id/emails/templates`](https://docs.bentonow.com/sequences_api#create-sequence-email) so you can add messages to a sequence via code. Pass the sequence prefix ID (e.g., `sequence_abc123`) plus the subject/HTML and any optional delay/snippet/editor fields.
Wraps [`POST /v1/fetch/sequences/:id/emails/templates`](https://docs.bentonow.com/sequences_api#create-sequence-email) so you can add messages to a sequence via code. Pass the sequence ID returned by `getSequences()` plus the subject/HTML and any optional delay/snippet/editor fields.

```javascript
const createdTemplate = await analytics.V1.Sequences.createSequenceEmail('sequence_abc123', {
const createdTemplate = await analytics.V1.Sequences.createSequenceEmail('123', {
subject: 'Welcome to Bento',
html: '<p>Hello {{ visitor.first_name }}</p>',
delay_interval: 'days',
Expand Down
92 changes: 45 additions & 47 deletions __tests__/broadcasts/broadcasts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,22 +146,15 @@ describe('BentoBroadcasts', () => {
describe('createBroadcast', () => {
test('successfully creates broadcast', async () => {
const mockResponse = {
data: [
results: 1,
failed: 0,
failures: [],
broadcasts: [
{
id: 'new-broadcast-1',
type: EntityType.EVENTS,
attributes: {
name: 'New Broadcast',
subject: 'New Subject',
content: '<p>Content</p>',
type: 'html',
from: {
name: 'Sender',
email: 'sender@example.com',
},
batch_size_per_hour: 100,
created_at: '2024-01-01T00:00:00Z',
},
id: 42,
template_id: 99,
name: 'New Broadcast',
dashboard_url: 'https://app.bentonow.com/account/emails/broadcasts/42/edit',
},
],
};
Expand All @@ -182,13 +175,15 @@ describe('BentoBroadcasts', () => {
},
]);

expect(result).toHaveLength(1);
// @ts-ignore
expect(result[0].attributes.name).toBe('New Broadcast');
expect(result.results).toBe(1);
expect(result.failed).toBe(0);
expect(result.broadcasts).toHaveLength(1);
expect(result.broadcasts?.[0].name).toBe('New Broadcast');
expect(result.broadcasts?.[0].id).toBe(42);
});

test('uses correct /batch/broadcasts endpoint for POST', async () => {
setupMockFetch({ data: [] });
setupMockFetch({ results: 0, failed: 0, broadcasts: [], failures: [] });

await analytics.V1.Broadcasts.createBroadcast([
{
Expand All @@ -208,27 +203,23 @@ describe('BentoBroadcasts', () => {
expect(lastFetchMethod).toBe('POST');
});

test('handles broadcast with segments and tags', async () => {
test('returns partial success with failures', async () => {
const mockResponse = {
data: [
results: 1,
failed: 1,
broadcasts: [
{
id: 'broadcast-2',
type: EntityType.EVENTS,
attributes: {
name: 'Segmented Broadcast',
subject: 'For Segment',
content: 'Content',
type: 'plain',
from: {
name: 'Sender',
email: 'sender@example.com',
},
inclusive_tags: 'tag1,tag2',
exclusive_tags: 'tag3',
segment_id: 'segment-123',
batch_size_per_hour: 50,
created_at: '2024-01-01T00:00:00Z',
},
id: 42,
template_id: 99,
name: 'Created draft',
dashboard_url: 'https://app.bentonow.com/account/emails/broadcasts/42/edit',
},
],
failures: [
{
index: 1,
name: 'Invalid draft',
error: 'batch_size_per_hour must be between 10 and 250000',
},
],
};
Expand All @@ -237,26 +228,33 @@ describe('BentoBroadcasts', () => {

const result = await analytics.V1.Broadcasts.createBroadcast([
{
name: 'Segmented Broadcast',
name: 'Created draft',
subject: 'For Segment',
content: 'Content',
type: 'plain',
from: {
name: 'Sender',
email: 'sender@example.com',
},
inclusive_tags: 'tag1,tag2',
exclusive_tags: 'tag3',
segment_id: 'segment-123',
batch_size_per_hour: 50,
},
{
name: 'Invalid draft',
subject: 'Bad',
content: 'Content',
type: 'plain',
from: {
name: 'Sender',
email: 'sender@example.com',
},
batch_size_per_hour: 1,
},
]);

expect(result).toHaveLength(1);
// @ts-ignore
expect(result[0].attributes.segment_id).toBe('segment-123');
// @ts-ignore
expect(result[0].attributes.inclusive_tags).toBe('tag1,tag2');
expect(result.results).toBe(1);
expect(result.failed).toBe(1);
expect(result.broadcasts).toHaveLength(1);
expect(result.failures?.[0].error).toContain('batch_size_per_hour');
});
});
});
29 changes: 6 additions & 23 deletions __tests__/commands/addField.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { expect, test, describe, beforeEach } from 'bun:test';
import { Analytics } from '../../src';
import { mockOptions } from '../helpers/mockClient';
import { mockSubscriberResponse } from '../helpers/mockResponses';
import { setupMockFetch } from '../helpers/mockFetch';

describe('BentoCommands - addField', () => {
Expand All @@ -11,34 +10,18 @@ describe('BentoCommands - addField', () => {
analytics = new Analytics(mockOptions);
});

test('successfully adds a field to a subscriber', async () => {
const email = 'test@example.com';
setupMockFetch(mockSubscriberResponse(email));

const result = await analytics.V1.Commands.addField({
email,
field: {
key: 'testField',
value: 'testValue'
}
});

expect(result).toBeDefined();
expect(result?.attributes.email).toBe(email);
});

test('returns null when response is empty', async () => {
setupMockFetch({ data: null });
test('successfully queues an add_field command', async () => {
setupMockFetch({ results: 1 });

const result = await analytics.V1.Commands.addField({
email: 'test@example.com',
field: {
key: 'testField',
value: 'testValue'
}
value: 'testValue',
},
});

expect(result).toBeNull();
expect(result).toBe(1);
});

test('handles server error gracefully', async () => {
Expand All @@ -54,4 +37,4 @@ describe('BentoCommands - addField', () => {
})
).rejects.toThrow();
});
});
});
23 changes: 5 additions & 18 deletions __tests__/commands/addTag.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { expect, test, describe, beforeEach } from 'bun:test';
import { Analytics } from '../../src';
import { mockOptions } from '../helpers/mockClient';
import { mockSubscriberResponse } from '../helpers/mockResponses';
import { setupMockFetch } from '../helpers/mockFetch';

describe('BentoCommands - addTag', () => {
Expand All @@ -11,27 +10,15 @@ describe('BentoCommands - addTag', () => {
analytics = new Analytics(mockOptions);
});

test('successfully adds a tag to a subscriber', async () => {
const email = 'test@example.com';
const tagName = 'TestTag';
setupMockFetch(mockSubscriberResponse(email, ['tag-123']));

const result = await analytics.V1.Commands.addTag({ email, tagName });

expect(result).toBeDefined();
expect(result?.attributes.email).toBe(email);
expect(result?.attributes.cached_tag_ids).toContain('tag-123');
});

test('returns null when response is empty', async () => {
setupMockFetch({ data: null });
test('successfully queues an add_tag command', async () => {
setupMockFetch({ results: 1 });

const result = await analytics.V1.Commands.addTag({
email: 'test@example.com',
tagName: 'TestTag'
tagName: 'TestTag',
});

expect(result).toBeNull();
expect(result).toBe(1);
});

test('handles server error gracefully', async () => {
Expand All @@ -44,4 +31,4 @@ describe('BentoCommands - addTag', () => {
})
).rejects.toThrow();
});
});
});
25 changes: 5 additions & 20 deletions __tests__/commands/changeEmail.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { expect, test, describe, beforeEach } from 'bun:test';
import { Analytics } from '../../src';
import { mockOptions } from '../helpers/mockClient';
import { mockSubscriberResponse } from '../helpers/mockResponses';
import { setupMockFetch } from '../helpers/mockFetch';

describe('BentoCommands - changeEmail', () => {
Expand All @@ -11,29 +10,15 @@ describe('BentoCommands - changeEmail', () => {
analytics = new Analytics(mockOptions);
});

test('successfully changes email address', async () => {
const oldEmail = 'old@example.com';
const newEmail = 'new@example.com';
setupMockFetch(mockSubscriberResponse(newEmail));

const result = await analytics.V1.Commands.changeEmail({
oldEmail,
newEmail
});

expect(result).toBeDefined();
expect(result?.attributes.email).toBe(newEmail);
});

test('returns null when response is empty', async () => {
setupMockFetch({ data: null });
test('successfully queues a change_email command', async () => {
setupMockFetch({ results: 1 });

const result = await analytics.V1.Commands.changeEmail({
oldEmail: 'old@example.com',
newEmail: 'new@example.com'
newEmail: 'new@example.com',
});

expect(result).toBeNull();
expect(result).toBe(1);
});

test('handles server error gracefully', async () => {
Expand All @@ -46,4 +31,4 @@ describe('BentoCommands - changeEmail', () => {
})
).rejects.toThrow();
});
});
});
24 changes: 5 additions & 19 deletions __tests__/commands/removeField.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { expect, test, describe, beforeEach } from 'bun:test';
import { Analytics } from '../../src';
import { mockOptions } from '../helpers/mockClient';
import { mockSubscriberResponse } from '../helpers/mockResponses';
import { setupMockFetch } from '../helpers/mockFetch';

describe('BentoCommands - removeField', () => {
Expand All @@ -11,28 +10,15 @@ describe('BentoCommands - removeField', () => {
analytics = new Analytics(mockOptions);
});

test('successfully removes a field from a subscriber', async () => {
const email = 'test@example.com';
setupMockFetch(mockSubscriberResponse(email));

const result = await analytics.V1.Commands.removeField({
email,
fieldName: 'testField'
});

expect(result).toBeDefined();
expect(result?.attributes.email).toBe(email);
});

test('returns null when response is empty', async () => {
setupMockFetch({ data: null });
test('successfully queues a remove_field command', async () => {
setupMockFetch({ results: 1 });

const result = await analytics.V1.Commands.removeField({
email: 'test@example.com',
fieldName: 'testField'
fieldName: 'testField',
});

expect(result).toBeNull();
expect(result).toBe(1);
});

test('handles server error gracefully', async () => {
Expand All @@ -45,4 +31,4 @@ describe('BentoCommands - removeField', () => {
})
).rejects.toThrow();
});
});
});
25 changes: 5 additions & 20 deletions __tests__/commands/removeTag.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { expect, test, describe, beforeEach } from 'bun:test';
import { Analytics } from '../../src';
import { mockOptions } from '../helpers/mockClient';
import { mockSubscriberResponse } from '../helpers/mockResponses';
import { setupMockFetch } from '../helpers/mockFetch';

describe('BentoCommands - removeTag', () => {
Expand All @@ -11,28 +10,14 @@ describe('BentoCommands - removeTag', () => {
analytics = new Analytics(mockOptions);
});

test('successfully removes a tag from a subscriber', async () => {
const email = 'test@example.com';
setupMockFetch(mockSubscriberResponse(email, []));

const result = await analytics.V1.Commands.removeTag({
email,
tagName: 'TestTag'
});

expect(result).toBeDefined();
expect(result?.attributes.email).toBe(email);
expect(result?.attributes.cached_tag_ids).toHaveLength(0);
});

test('returns null when response is empty', async () => {
setupMockFetch({ data: null });
test('successfully queues a remove_tag command', async () => {
setupMockFetch({ results: 1 });

const result = await analytics.V1.Commands.removeTag({
email: 'test@example.com',
tagName: 'TestTag'
tagName: 'TestTag',
});

expect(result).toBeNull();
expect(result).toBe(1);
});
});
});
Loading
Loading