|
@@ -1,13 +1,15 @@
|
|
|
import { mockDeep, mockReset } from 'jest-mock-extended';
|
|
|
import { PrismaService } from '../prisma/prisma.service';
|
|
|
import {
|
|
|
- SHORTCODE_ALREADY_EXISTS,
|
|
|
- SHORTCODE_INVALID_JSON,
|
|
|
+ SHORTCODE_INVALID_PROPERTIES_JSON,
|
|
|
+ SHORTCODE_INVALID_REQUEST_JSON,
|
|
|
SHORTCODE_NOT_FOUND,
|
|
|
+ SHORTCODE_PROPERTIES_NOT_FOUND,
|
|
|
} from 'src/errors';
|
|
|
import { Shortcode } from './shortcode.model';
|
|
|
import { ShortcodeService } from './shortcode.service';
|
|
|
import { UserService } from 'src/user/user.service';
|
|
|
+import { AuthUser } from 'src/types/AuthUser';
|
|
|
|
|
|
const mockPrisma = mockDeep<PrismaService>();
|
|
|
|
|
@@ -22,7 +24,7 @@ const mockFB = {
|
|
|
doc: mockDocFunc,
|
|
|
},
|
|
|
};
|
|
|
-const mockUserService = new UserService(mockFB as any, mockPubSub as any);
|
|
|
+const mockUserService = new UserService(mockPrisma as any, mockPubSub as any);
|
|
|
|
|
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
|
// @ts-ignore
|
|
@@ -38,18 +40,34 @@ beforeEach(() => {
|
|
|
});
|
|
|
const createdOn = new Date();
|
|
|
|
|
|
-const shortCodeWithOutUser = {
|
|
|
+const user: AuthUser = {
|
|
|
+ uid: '123344',
|
|
|
+ email: 'dwight@dundermifflin.com',
|
|
|
+ displayName: 'Dwight Schrute',
|
|
|
+ photoURL: 'https://en.wikipedia.org/wiki/Dwight_Schrute',
|
|
|
+ isAdmin: false,
|
|
|
+ refreshToken: 'hbfvdkhjbvkdvdfjvbnkhjb',
|
|
|
+ createdOn: createdOn,
|
|
|
+ currentGQLSession: {},
|
|
|
+ currentRESTSession: {},
|
|
|
+};
|
|
|
+
|
|
|
+const mockEmbed = {
|
|
|
id: '123',
|
|
|
request: '{}',
|
|
|
+ embedProperties: '{}',
|
|
|
createdOn: createdOn,
|
|
|
- creatorUid: null,
|
|
|
+ creatorUid: user.uid,
|
|
|
+ updatedOn: createdOn,
|
|
|
};
|
|
|
|
|
|
-const shortCodeWithUser = {
|
|
|
+const mockShortcode = {
|
|
|
id: '123',
|
|
|
request: '{}',
|
|
|
+ embedProperties: null,
|
|
|
createdOn: createdOn,
|
|
|
- creatorUid: 'user_uid_1',
|
|
|
+ creatorUid: user.uid,
|
|
|
+ updatedOn: createdOn,
|
|
|
};
|
|
|
|
|
|
const shortcodes = [
|
|
@@ -58,33 +76,38 @@ const shortcodes = [
|
|
|
request: {
|
|
|
hello: 'there',
|
|
|
},
|
|
|
- creatorUid: 'testuser',
|
|
|
+ embedProperties: {
|
|
|
+ foo: 'bar',
|
|
|
+ },
|
|
|
+ creatorUid: user.uid,
|
|
|
createdOn: new Date(),
|
|
|
+ updatedOn: createdOn,
|
|
|
},
|
|
|
{
|
|
|
id: 'blablabla1',
|
|
|
request: {
|
|
|
hello: 'there',
|
|
|
},
|
|
|
- creatorUid: 'testuser',
|
|
|
+ embedProperties: {
|
|
|
+ foo: 'bar',
|
|
|
+ },
|
|
|
+ creatorUid: user.uid,
|
|
|
createdOn: new Date(),
|
|
|
+ updatedOn: createdOn,
|
|
|
},
|
|
|
];
|
|
|
|
|
|
describe('ShortcodeService', () => {
|
|
|
describe('getShortCode', () => {
|
|
|
- test('should return a valid shortcode with valid shortcode ID', async () => {
|
|
|
- mockPrisma.shortcode.findFirstOrThrow.mockResolvedValueOnce(
|
|
|
- shortCodeWithOutUser,
|
|
|
- );
|
|
|
+ test('should return a valid Shortcode with valid Shortcode ID', async () => {
|
|
|
+ mockPrisma.shortcode.findFirstOrThrow.mockResolvedValueOnce(mockEmbed);
|
|
|
|
|
|
- const result = await shortcodeService.getShortCode(
|
|
|
- shortCodeWithOutUser.id,
|
|
|
- );
|
|
|
+ const result = await shortcodeService.getShortCode(mockEmbed.id);
|
|
|
expect(result).toEqualRight(<Shortcode>{
|
|
|
- id: shortCodeWithOutUser.id,
|
|
|
- createdOn: shortCodeWithOutUser.createdOn,
|
|
|
- request: JSON.stringify(shortCodeWithOutUser.request),
|
|
|
+ id: mockEmbed.id,
|
|
|
+ createdOn: mockEmbed.createdOn,
|
|
|
+ request: JSON.stringify(mockEmbed.request),
|
|
|
+ properties: JSON.stringify(mockEmbed.embedProperties),
|
|
|
});
|
|
|
});
|
|
|
|
|
@@ -99,10 +122,10 @@ describe('ShortcodeService', () => {
|
|
|
});
|
|
|
|
|
|
describe('fetchUserShortCodes', () => {
|
|
|
- test('should return list of shortcodes with valid inputs and no cursor', async () => {
|
|
|
+ test('should return list of Shortcode with valid inputs and no cursor', async () => {
|
|
|
mockPrisma.shortcode.findMany.mockResolvedValueOnce(shortcodes);
|
|
|
|
|
|
- const result = await shortcodeService.fetchUserShortCodes('testuser', {
|
|
|
+ const result = await shortcodeService.fetchUserShortCodes(user.uid, {
|
|
|
cursor: null,
|
|
|
take: 10,
|
|
|
});
|
|
@@ -110,20 +133,22 @@ describe('ShortcodeService', () => {
|
|
|
{
|
|
|
id: shortcodes[0].id,
|
|
|
request: JSON.stringify(shortcodes[0].request),
|
|
|
+ properties: JSON.stringify(shortcodes[0].embedProperties),
|
|
|
createdOn: shortcodes[0].createdOn,
|
|
|
},
|
|
|
{
|
|
|
id: shortcodes[1].id,
|
|
|
request: JSON.stringify(shortcodes[1].request),
|
|
|
+ properties: JSON.stringify(shortcodes[1].embedProperties),
|
|
|
createdOn: shortcodes[1].createdOn,
|
|
|
},
|
|
|
]);
|
|
|
});
|
|
|
|
|
|
- test('should return list of shortcodes with valid inputs and cursor', async () => {
|
|
|
+ test('should return list of Shortcode with valid inputs and cursor', async () => {
|
|
|
mockPrisma.shortcode.findMany.mockResolvedValue([shortcodes[1]]);
|
|
|
|
|
|
- const result = await shortcodeService.fetchUserShortCodes('testuser', {
|
|
|
+ const result = await shortcodeService.fetchUserShortCodes(user.uid, {
|
|
|
cursor: 'blablabla',
|
|
|
take: 10,
|
|
|
});
|
|
@@ -131,6 +156,7 @@ describe('ShortcodeService', () => {
|
|
|
{
|
|
|
id: shortcodes[1].id,
|
|
|
request: JSON.stringify(shortcodes[1].request),
|
|
|
+ properties: JSON.stringify(shortcodes[1].embedProperties),
|
|
|
createdOn: shortcodes[1].createdOn,
|
|
|
},
|
|
|
]);
|
|
@@ -139,7 +165,7 @@ describe('ShortcodeService', () => {
|
|
|
test('should return an empty array for an invalid cursor', async () => {
|
|
|
mockPrisma.shortcode.findMany.mockResolvedValue([]);
|
|
|
|
|
|
- const result = await shortcodeService.fetchUserShortCodes('testuser', {
|
|
|
+ const result = await shortcodeService.fetchUserShortCodes(user.uid, {
|
|
|
cursor: 'invalidcursor',
|
|
|
take: 10,
|
|
|
});
|
|
@@ -171,77 +197,111 @@ describe('ShortcodeService', () => {
|
|
|
});
|
|
|
|
|
|
describe('createShortcode', () => {
|
|
|
- test('should throw SHORTCODE_INVALID_JSON error if incoming request data is invalid', async () => {
|
|
|
+ test('should throw SHORTCODE_INVALID_REQUEST_JSON error if incoming request data is invalid', async () => {
|
|
|
const result = await shortcodeService.createShortcode(
|
|
|
'invalidRequest',
|
|
|
- 'user_uid_1',
|
|
|
+ null,
|
|
|
+ user,
|
|
|
);
|
|
|
- expect(result).toEqualLeft(SHORTCODE_INVALID_JSON);
|
|
|
+ expect(result).toEqualLeft(SHORTCODE_INVALID_REQUEST_JSON);
|
|
|
});
|
|
|
|
|
|
- test('should successfully create a new shortcode with valid user uid', async () => {
|
|
|
- // generateUniqueShortCodeID --> getShortCode
|
|
|
+ test('should throw SHORTCODE_INVALID_PROPERTIES_JSON error if incoming properties data is invalid', async () => {
|
|
|
+ const result = await shortcodeService.createShortcode(
|
|
|
+ '{}',
|
|
|
+ 'invalid_data',
|
|
|
+ user,
|
|
|
+ );
|
|
|
+ expect(result).toEqualLeft(SHORTCODE_INVALID_PROPERTIES_JSON);
|
|
|
+ });
|
|
|
+
|
|
|
+ test('should successfully create a new Embed with valid user uid', async () => {
|
|
|
+ // generateUniqueShortCodeID --> getShortcode
|
|
|
mockPrisma.shortcode.findFirstOrThrow.mockRejectedValueOnce(
|
|
|
'NotFoundError',
|
|
|
);
|
|
|
- mockPrisma.shortcode.create.mockResolvedValueOnce(shortCodeWithUser);
|
|
|
+ mockPrisma.shortcode.create.mockResolvedValueOnce(mockEmbed);
|
|
|
|
|
|
- const result = await shortcodeService.createShortcode('{}', 'user_uid_1');
|
|
|
- expect(result).toEqualRight({
|
|
|
- id: shortCodeWithUser.id,
|
|
|
- createdOn: shortCodeWithUser.createdOn,
|
|
|
- request: JSON.stringify(shortCodeWithUser.request),
|
|
|
+ const result = await shortcodeService.createShortcode('{}', '{}', user);
|
|
|
+ expect(result).toEqualRight(<Shortcode>{
|
|
|
+ id: mockEmbed.id,
|
|
|
+ createdOn: mockEmbed.createdOn,
|
|
|
+ request: JSON.stringify(mockEmbed.request),
|
|
|
+ properties: JSON.stringify(mockEmbed.embedProperties),
|
|
|
});
|
|
|
});
|
|
|
|
|
|
- test('should successfully create a new shortcode with null user uid', async () => {
|
|
|
- // generateUniqueShortCodeID --> getShortCode
|
|
|
+ test('should successfully create a new ShortCode with valid user uid', async () => {
|
|
|
+ // generateUniqueShortCodeID --> getShortcode
|
|
|
mockPrisma.shortcode.findFirstOrThrow.mockRejectedValueOnce(
|
|
|
'NotFoundError',
|
|
|
);
|
|
|
- mockPrisma.shortcode.create.mockResolvedValueOnce(shortCodeWithUser);
|
|
|
+ mockPrisma.shortcode.create.mockResolvedValueOnce(mockShortcode);
|
|
|
|
|
|
- const result = await shortcodeService.createShortcode('{}', null);
|
|
|
- expect(result).toEqualRight({
|
|
|
- id: shortCodeWithUser.id,
|
|
|
- createdOn: shortCodeWithUser.createdOn,
|
|
|
- request: JSON.stringify(shortCodeWithOutUser.request),
|
|
|
+ const result = await shortcodeService.createShortcode('{}', null, user);
|
|
|
+ expect(result).toEqualRight(<Shortcode>{
|
|
|
+ id: mockShortcode.id,
|
|
|
+ createdOn: mockShortcode.createdOn,
|
|
|
+ request: JSON.stringify(mockShortcode.request),
|
|
|
+ properties: mockShortcode.embedProperties,
|
|
|
});
|
|
|
});
|
|
|
|
|
|
- test('should send pubsub message to `shortcode/{uid}/created` on successful creation of shortcode', async () => {
|
|
|
- // generateUniqueShortCodeID --> getShortCode
|
|
|
+ test('should send pubsub message to `shortcode/{uid}/created` on successful creation of a Shortcode', async () => {
|
|
|
+ // generateUniqueShortCodeID --> getShortcode
|
|
|
mockPrisma.shortcode.findFirstOrThrow.mockRejectedValueOnce(
|
|
|
'NotFoundError',
|
|
|
);
|
|
|
- mockPrisma.shortcode.create.mockResolvedValueOnce(shortCodeWithUser);
|
|
|
+ mockPrisma.shortcode.create.mockResolvedValueOnce(mockShortcode);
|
|
|
+
|
|
|
+ const result = await shortcodeService.createShortcode('{}', null, user);
|
|
|
|
|
|
- const result = await shortcodeService.createShortcode('{}', 'user_uid_1');
|
|
|
expect(mockPubSub.publish).toHaveBeenCalledWith(
|
|
|
- `shortcode/${shortCodeWithUser.creatorUid}/created`,
|
|
|
- {
|
|
|
- id: shortCodeWithUser.id,
|
|
|
- createdOn: shortCodeWithUser.createdOn,
|
|
|
- request: JSON.stringify(shortCodeWithUser.request),
|
|
|
+ `shortcode/${mockShortcode.creatorUid}/created`,
|
|
|
+ <Shortcode>{
|
|
|
+ id: mockShortcode.id,
|
|
|
+ createdOn: mockShortcode.createdOn,
|
|
|
+ request: JSON.stringify(mockShortcode.request),
|
|
|
+ properties: mockShortcode.embedProperties,
|
|
|
+ },
|
|
|
+ );
|
|
|
+ });
|
|
|
+
|
|
|
+ test('should send pubsub message to `shortcode/{uid}/created` on successful creation of an Embed', async () => {
|
|
|
+ // generateUniqueShortCodeID --> getShortcode
|
|
|
+ mockPrisma.shortcode.findFirstOrThrow.mockRejectedValueOnce(
|
|
|
+ 'NotFoundError',
|
|
|
+ );
|
|
|
+ mockPrisma.shortcode.create.mockResolvedValueOnce(mockEmbed);
|
|
|
+
|
|
|
+ const result = await shortcodeService.createShortcode('{}', '{}', user);
|
|
|
+
|
|
|
+ expect(mockPubSub.publish).toHaveBeenCalledWith(
|
|
|
+ `shortcode/${mockEmbed.creatorUid}/created`,
|
|
|
+ <Shortcode>{
|
|
|
+ id: mockEmbed.id,
|
|
|
+ createdOn: mockEmbed.createdOn,
|
|
|
+ request: JSON.stringify(mockEmbed.request),
|
|
|
+ properties: JSON.stringify(mockEmbed.embedProperties),
|
|
|
},
|
|
|
);
|
|
|
});
|
|
|
});
|
|
|
|
|
|
describe('revokeShortCode', () => {
|
|
|
- test('should return true on successful deletion of shortcode with valid inputs', async () => {
|
|
|
- mockPrisma.shortcode.delete.mockResolvedValueOnce(shortCodeWithUser);
|
|
|
+ test('should return true on successful deletion of Shortcode with valid inputs', async () => {
|
|
|
+ mockPrisma.shortcode.delete.mockResolvedValueOnce(mockEmbed);
|
|
|
|
|
|
const result = await shortcodeService.revokeShortCode(
|
|
|
- shortCodeWithUser.id,
|
|
|
- shortCodeWithUser.creatorUid,
|
|
|
+ mockEmbed.id,
|
|
|
+ mockEmbed.creatorUid,
|
|
|
);
|
|
|
|
|
|
expect(mockPrisma.shortcode.delete).toHaveBeenCalledWith({
|
|
|
where: {
|
|
|
creator_uid_shortcode_unique: {
|
|
|
- creatorUid: shortCodeWithUser.creatorUid,
|
|
|
- id: shortCodeWithUser.id,
|
|
|
+ creatorUid: mockEmbed.creatorUid,
|
|
|
+ id: mockEmbed.id,
|
|
|
},
|
|
|
},
|
|
|
});
|
|
@@ -249,52 +309,53 @@ describe('ShortcodeService', () => {
|
|
|
expect(result).toEqualRight(true);
|
|
|
});
|
|
|
|
|
|
- test('should return SHORTCODE_NOT_FOUND error when shortcode is invalid and user uid is valid', async () => {
|
|
|
+ test('should return SHORTCODE_NOT_FOUND error when Shortcode is invalid and user uid is valid', async () => {
|
|
|
mockPrisma.shortcode.delete.mockRejectedValue('RecordNotFound');
|
|
|
expect(
|
|
|
shortcodeService.revokeShortCode('invalid', 'testuser'),
|
|
|
).resolves.toEqualLeft(SHORTCODE_NOT_FOUND);
|
|
|
});
|
|
|
|
|
|
- test('should return SHORTCODE_NOT_FOUND error when shortcode is valid and user uid is invalid', async () => {
|
|
|
+ test('should return SHORTCODE_NOT_FOUND error when Shortcode is valid and user uid is invalid', async () => {
|
|
|
mockPrisma.shortcode.delete.mockRejectedValue('RecordNotFound');
|
|
|
expect(
|
|
|
shortcodeService.revokeShortCode('blablablabla', 'invalidUser'),
|
|
|
).resolves.toEqualLeft(SHORTCODE_NOT_FOUND);
|
|
|
});
|
|
|
|
|
|
- test('should return SHORTCODE_NOT_FOUND error when both shortcode and user uid are invalid', async () => {
|
|
|
+ test('should return SHORTCODE_NOT_FOUND error when both Shortcode and user uid are invalid', async () => {
|
|
|
mockPrisma.shortcode.delete.mockRejectedValue('RecordNotFound');
|
|
|
expect(
|
|
|
shortcodeService.revokeShortCode('invalid', 'invalid'),
|
|
|
).resolves.toEqualLeft(SHORTCODE_NOT_FOUND);
|
|
|
});
|
|
|
|
|
|
- test('should send pubsub message to `shortcode/{uid}/revoked` on successful deletion of shortcode', async () => {
|
|
|
- mockPrisma.shortcode.delete.mockResolvedValueOnce(shortCodeWithUser);
|
|
|
+ test('should send pubsub message to `shortcode/{uid}/revoked` on successful deletion of Shortcode', async () => {
|
|
|
+ mockPrisma.shortcode.delete.mockResolvedValueOnce(mockEmbed);
|
|
|
|
|
|
const result = await shortcodeService.revokeShortCode(
|
|
|
- shortCodeWithUser.id,
|
|
|
- shortCodeWithUser.creatorUid,
|
|
|
+ mockEmbed.id,
|
|
|
+ mockEmbed.creatorUid,
|
|
|
);
|
|
|
|
|
|
expect(mockPubSub.publish).toHaveBeenCalledWith(
|
|
|
- `shortcode/${shortCodeWithUser.creatorUid}/revoked`,
|
|
|
+ `shortcode/${mockEmbed.creatorUid}/revoked`,
|
|
|
{
|
|
|
- id: shortCodeWithUser.id,
|
|
|
- createdOn: shortCodeWithUser.createdOn,
|
|
|
- request: JSON.stringify(shortCodeWithUser.request),
|
|
|
+ id: mockEmbed.id,
|
|
|
+ createdOn: mockEmbed.createdOn,
|
|
|
+ request: JSON.stringify(mockEmbed.request),
|
|
|
+ properties: JSON.stringify(mockEmbed.embedProperties),
|
|
|
},
|
|
|
);
|
|
|
});
|
|
|
});
|
|
|
|
|
|
describe('deleteUserShortCodes', () => {
|
|
|
- test('should successfully delete all users shortcodes with valid user uid', async () => {
|
|
|
+ test('should successfully delete all users Shortcodes with valid user uid', async () => {
|
|
|
mockPrisma.shortcode.deleteMany.mockResolvedValueOnce({ count: 1 });
|
|
|
|
|
|
const result = await shortcodeService.deleteUserShortCodes(
|
|
|
- shortCodeWithUser.creatorUid,
|
|
|
+ mockEmbed.creatorUid,
|
|
|
);
|
|
|
expect(result).toEqual(1);
|
|
|
});
|
|
@@ -303,9 +364,81 @@ describe('ShortcodeService', () => {
|
|
|
mockPrisma.shortcode.deleteMany.mockResolvedValueOnce({ count: 0 });
|
|
|
|
|
|
const result = await shortcodeService.deleteUserShortCodes(
|
|
|
- shortCodeWithUser.creatorUid,
|
|
|
+ mockEmbed.creatorUid,
|
|
|
);
|
|
|
expect(result).toEqual(0);
|
|
|
});
|
|
|
});
|
|
|
+
|
|
|
+ describe('updateShortcode', () => {
|
|
|
+ test('should return SHORTCODE_PROPERTIES_NOT_FOUND error when updatedProps in invalid', async () => {
|
|
|
+ const result = await shortcodeService.updateEmbedProperties(
|
|
|
+ mockEmbed.id,
|
|
|
+ user.uid,
|
|
|
+ '',
|
|
|
+ );
|
|
|
+ expect(result).toEqualLeft(SHORTCODE_PROPERTIES_NOT_FOUND);
|
|
|
+ });
|
|
|
+
|
|
|
+ test('should return SHORTCODE_PROPERTIES_NOT_FOUND error when updatedProps in invalid JSON format', async () => {
|
|
|
+ const result = await shortcodeService.updateEmbedProperties(
|
|
|
+ mockEmbed.id,
|
|
|
+ user.uid,
|
|
|
+ '{kk',
|
|
|
+ );
|
|
|
+ expect(result).toEqualLeft(SHORTCODE_INVALID_PROPERTIES_JSON);
|
|
|
+ });
|
|
|
+
|
|
|
+ test('should return SHORTCODE_NOT_FOUND error when Shortcode ID is invalid', async () => {
|
|
|
+ mockPrisma.shortcode.update.mockRejectedValue('RecordNotFound');
|
|
|
+ const result = await shortcodeService.updateEmbedProperties(
|
|
|
+ 'invalidID',
|
|
|
+ user.uid,
|
|
|
+ '{}',
|
|
|
+ );
|
|
|
+ expect(result).toEqualLeft(SHORTCODE_NOT_FOUND);
|
|
|
+ });
|
|
|
+
|
|
|
+ test('should successfully update a Shortcodes with valid inputs', async () => {
|
|
|
+ mockPrisma.shortcode.update.mockResolvedValueOnce({
|
|
|
+ ...mockEmbed,
|
|
|
+ embedProperties: '{"foo":"bar"}',
|
|
|
+ });
|
|
|
+
|
|
|
+ const result = await shortcodeService.updateEmbedProperties(
|
|
|
+ mockEmbed.id,
|
|
|
+ user.uid,
|
|
|
+ '{"foo":"bar"}',
|
|
|
+ );
|
|
|
+ expect(result).toEqualRight({
|
|
|
+ id: mockEmbed.id,
|
|
|
+ createdOn: mockEmbed.createdOn,
|
|
|
+ request: JSON.stringify(mockEmbed.request),
|
|
|
+ properties: JSON.stringify('{"foo":"bar"}'),
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ test('should send pubsub message to `shortcode/{uid}/updated` on successful Update of Shortcode', async () => {
|
|
|
+ mockPrisma.shortcode.update.mockResolvedValueOnce({
|
|
|
+ ...mockEmbed,
|
|
|
+ embedProperties: '{"foo":"bar"}',
|
|
|
+ });
|
|
|
+
|
|
|
+ const result = await shortcodeService.updateEmbedProperties(
|
|
|
+ mockEmbed.id,
|
|
|
+ user.uid,
|
|
|
+ '{"foo":"bar"}',
|
|
|
+ );
|
|
|
+
|
|
|
+ expect(mockPubSub.publish).toHaveBeenCalledWith(
|
|
|
+ `shortcode/${mockEmbed.creatorUid}/updated`,
|
|
|
+ {
|
|
|
+ id: mockEmbed.id,
|
|
|
+ createdOn: mockEmbed.createdOn,
|
|
|
+ request: JSON.stringify(mockEmbed.request),
|
|
|
+ properties: JSON.stringify('{"foo":"bar"}'),
|
|
|
+ },
|
|
|
+ );
|
|
|
+ });
|
|
|
+ });
|
|
|
});
|