opticedge-cloud-utils 1.1.21 → 1.1.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/package.json +1 -1
  2. package/tsconfig.json +1 -1
  3. package/dist/tests/auth.test.d.ts +0 -1
  4. package/dist/tests/auth.test.js +0 -79
  5. package/dist/tests/chunk.test.d.ts +0 -1
  6. package/dist/tests/chunk.test.js +0 -45
  7. package/dist/tests/db/mongo.test.d.ts +0 -1
  8. package/dist/tests/db/mongo.test.js +0 -43
  9. package/dist/tests/db/mongo2.test.d.ts +0 -1
  10. package/dist/tests/db/mongo2.test.js +0 -49
  11. package/dist/tests/db/mongo3.test.d.ts +0 -1
  12. package/dist/tests/db/mongo3.test.js +0 -60
  13. package/dist/tests/env.test.d.ts +0 -1
  14. package/dist/tests/env.test.js +0 -17
  15. package/dist/tests/number.test.d.ts +0 -1
  16. package/dist/tests/number.test.js +0 -30
  17. package/dist/tests/parser.test.d.ts +0 -1
  18. package/dist/tests/parser.test.js +0 -24
  19. package/dist/tests/pub.test.d.ts +0 -1
  20. package/dist/tests/pub.test.js +0 -102
  21. package/dist/tests/regex.test.d.ts +0 -1
  22. package/dist/tests/regex.test.js +0 -60
  23. package/dist/tests/retry.test.d.ts +0 -1
  24. package/dist/tests/retry.test.js +0 -339
  25. package/dist/tests/secrets.test.d.ts +0 -1
  26. package/dist/tests/secrets.test.js +0 -38
  27. package/dist/tests/task.test.d.ts +0 -1
  28. package/dist/tests/task.test.js +0 -262
  29. package/dist/tests/tw/utils.test.d.ts +0 -1
  30. package/dist/tests/tw/utils.test.js +0 -26
  31. package/dist/tests/tw/wallet.test.d.ts +0 -1
  32. package/dist/tests/tw/wallet.test.js +0 -108
  33. package/dist/tests/validator.d.ts +0 -1
  34. package/dist/tests/validator.js +0 -34
  35. /package/dist/{src/auth.d.ts → auth.d.ts} +0 -0
  36. /package/dist/{src/auth.js → auth.js} +0 -0
  37. /package/dist/{src/chunk.d.ts → chunk.d.ts} +0 -0
  38. /package/dist/{src/chunk.js → chunk.js} +0 -0
  39. /package/dist/{src/db → db}/mongo.d.ts +0 -0
  40. /package/dist/{src/db → db}/mongo.js +0 -0
  41. /package/dist/{src/db → db}/mongo2.d.ts +0 -0
  42. /package/dist/{src/db → db}/mongo2.js +0 -0
  43. /package/dist/{src/db → db}/mongo3.d.ts +0 -0
  44. /package/dist/{src/db → db}/mongo3.js +0 -0
  45. /package/dist/{src/env.d.ts → env.d.ts} +0 -0
  46. /package/dist/{src/env.js → env.js} +0 -0
  47. /package/dist/{src/index.d.ts → index.d.ts} +0 -0
  48. /package/dist/{src/index.js → index.js} +0 -0
  49. /package/dist/{src/number.d.ts → number.d.ts} +0 -0
  50. /package/dist/{src/number.js → number.js} +0 -0
  51. /package/dist/{src/parser.d.ts → parser.d.ts} +0 -0
  52. /package/dist/{src/parser.js → parser.js} +0 -0
  53. /package/dist/{src/pub.d.ts → pub.d.ts} +0 -0
  54. /package/dist/{src/pub.js → pub.js} +0 -0
  55. /package/dist/{src/regex.d.ts → regex.d.ts} +0 -0
  56. /package/dist/{src/regex.js → regex.js} +0 -0
  57. /package/dist/{src/retry.d.ts → retry.d.ts} +0 -0
  58. /package/dist/{src/retry.js → retry.js} +0 -0
  59. /package/dist/{src/secrets.d.ts → secrets.d.ts} +0 -0
  60. /package/dist/{src/secrets.js → secrets.js} +0 -0
  61. /package/dist/{src/task.d.ts → task.d.ts} +0 -0
  62. /package/dist/{src/task.js → task.js} +0 -0
  63. /package/dist/{src/tw → tw}/utils.d.ts +0 -0
  64. /package/dist/{src/tw → tw}/utils.js +0 -0
  65. /package/dist/{src/tw → tw}/wallet.d.ts +0 -0
  66. /package/dist/{src/tw → tw}/wallet.js +0 -0
  67. /package/dist/{src/validator.d.ts → validator.d.ts} +0 -0
  68. /package/dist/{src/validator.js → validator.js} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opticedge-cloud-utils",
3
- "version": "1.1.21",
3
+ "version": "1.1.22",
4
4
  "description": "Common utilities for cloud functions",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/tsconfig.json CHANGED
@@ -12,6 +12,6 @@
12
12
  "forceConsistentCasingInFileNames": true,
13
13
  "types": ["node", "jest"]
14
14
  },
15
- "include": ["src", "tests"],
15
+ "include": ["src"],
16
16
  "exclude": ["node_modules", "dist"]
17
17
  }
@@ -1 +0,0 @@
1
- export {};
@@ -1,79 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const auth_1 = require("../src/auth");
4
- // Mock the google-auth-library
5
- jest.mock('google-auth-library', () => {
6
- return {
7
- OAuth2Client: jest.fn().mockImplementation(() => ({
8
- verifyIdToken: jest.fn(({ idToken, audience }) => {
9
- if (idToken === 'valid-token' && audience === 'audience') {
10
- return {
11
- getPayload: () => ({
12
- email: 'allowed@example.com'
13
- })
14
- };
15
- }
16
- else if (idToken === 'wrong-email-token' && audience === 'audience') {
17
- return {
18
- getPayload: () => ({
19
- email: 'unauthorized@example.com'
20
- })
21
- };
22
- }
23
- throw new Error('Invalid token');
24
- })
25
- }))
26
- };
27
- });
28
- describe('verifyRequest', () => {
29
- it('returns true for valid token and matching email', async () => {
30
- const mockReq = {
31
- headers: {
32
- authorization: 'Bearer valid-token'
33
- }
34
- };
35
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
36
- const result = await (0, auth_1.verifyRequest)(mockReq, {
37
- allowedAudience: 'audience',
38
- allowedServiceAccount: 'allowed@example.com'
39
- });
40
- expect(result).toBe(true);
41
- });
42
- it('returns false for invalid token', async () => {
43
- const mockReq = {
44
- headers: {
45
- authorization: 'Bearer invalid-token'
46
- }
47
- };
48
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
49
- const result = await (0, auth_1.verifyRequest)(mockReq, {
50
- allowedAudience: 'audience',
51
- allowedServiceAccount: 'allowed@example.com'
52
- });
53
- expect(result).toBe(false);
54
- });
55
- it('returns false for missing authorization header', async () => {
56
- const mockReq = {
57
- headers: {}
58
- };
59
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
60
- const result = await (0, auth_1.verifyRequest)(mockReq, {
61
- allowedAudience: 'audience',
62
- allowedServiceAccount: 'allowed@example.com'
63
- });
64
- expect(result).toBe(false);
65
- });
66
- it('returns false for incorrect email', async () => {
67
- const mockReq = {
68
- headers: {
69
- authorization: 'Bearer wrong-email-token'
70
- }
71
- };
72
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
73
- const result = await (0, auth_1.verifyRequest)(mockReq, {
74
- allowedAudience: 'audience',
75
- allowedServiceAccount: 'allowed@example.com'
76
- });
77
- expect(result).toBe(false);
78
- });
79
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,45 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const chunk_1 = require("../src/chunk");
4
- describe('chunkByBytes', () => {
5
- test('splits array into chunks based on byte size', () => {
6
- const arr = [
7
- { id: 'a', val: 'x'.repeat(100) },
8
- { id: 'b', val: 'y'.repeat(100) },
9
- { id: 'c', val: 'z'.repeat(100) }
10
- ];
11
- const chunks = (0, chunk_1.chunkByBytes)(arr, 200); // 200 bytes max per chunk
12
- expect(chunks.length).toBeGreaterThan(1); // should split
13
- expect(chunks.flat()).toEqual(arr); // all items present
14
- });
15
- test('puts single large item in its own chunk', () => {
16
- const arr = [{ id: 'big', val: 'x'.repeat(1000) }];
17
- const chunks = (0, chunk_1.chunkByBytes)(arr, 100);
18
- expect(chunks).toEqual([arr]); // large item pushed alone
19
- });
20
- test('does not split if all items fit within maxBytes', () => {
21
- const arr = [
22
- { id: 'a', val: 'x' },
23
- { id: 'b', val: 'y' }
24
- ];
25
- const chunks = (0, chunk_1.chunkByBytes)(arr, 1000);
26
- expect(chunks).toEqual([arr]);
27
- });
28
- test('uses default maxBytes if not provided', () => {
29
- const arr = [{ id: 'a', val: 'x'.repeat(10) }];
30
- // call without maxBytes
31
- const chunks = (0, chunk_1.chunkByBytes)(arr);
32
- expect(chunks.flat()).toEqual(arr); // all items present
33
- });
34
- test('flushes current chunk when a single item exceeds maxBytes', () => {
35
- const arr = [
36
- { id: '1', val: 'x'.repeat(50) }, // first small item
37
- { id: '2', val: 'y'.repeat(200) } // oversized item
38
- ];
39
- // set maxBytes small enough to trigger oversized item
40
- const chunks = (0, chunk_1.chunkByBytes)(arr, 100);
41
- expect(chunks.length).toBe(2); // first small chunk + oversized item alone
42
- expect(chunks[0]).toEqual([arr[0]]); // first item in first chunk
43
- expect(chunks[1]).toEqual([arr[1]]); // second item alone
44
- });
45
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,43 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const mongo_1 = require("../../src/db/mongo");
4
- const mongodb_1 = require("mongodb");
5
- jest.mock('mongodb');
6
- const mockDb = {
7
- collection: jest.fn()
8
- };
9
- const mockConnect = jest.fn();
10
- const mockClient = {
11
- connect: mockConnect,
12
- db: jest.fn().mockReturnValue(mockDb)
13
- };
14
- beforeEach(() => {
15
- jest.clearAllMocks();
16
- mongodb_1.MongoClient.mockImplementation(() => mockClient);
17
- });
18
- describe('Mongo Utils', () => {
19
- it('should connect to MongoDB and store client/db', async () => {
20
- await (0, mongo_1.connectToMongo)('mongo-uri', 'test-db');
21
- expect(mockConnect).toHaveBeenCalled();
22
- expect(mockClient.db).toHaveBeenCalledWith('test-db');
23
- });
24
- it('should return a collection when db is initialized', async () => {
25
- await (0, mongo_1.connectToMongo)('mongo-uri', 'test-db');
26
- (0, mongo_1.getCollection)('users');
27
- expect(mockDb.collection).toHaveBeenCalledWith('users');
28
- });
29
- it('getDb should return the initialized Db instance', async () => {
30
- await (0, mongo_1.connectToMongo)('mongo-uri', 'test-db');
31
- const got = (0, mongo_1.getDb)();
32
- expect(got).toBe(mockDb);
33
- });
34
- it('should throw error if db is not initialized (getCollection/getDb)', () => {
35
- jest.isolateModules(() => {
36
- // require a fresh copy of the module so module-level state is uninitialized
37
- // eslint-disable-next-line @typescript-eslint/no-require-imports
38
- const mod = require('../../src/db/mongo');
39
- expect(() => mod.getCollection('users')).toThrow(/Mongo not initialized/);
40
- expect(() => mod.getDb()).toThrow(/Mongo not initialized/);
41
- });
42
- });
43
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,49 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const mongo2_1 = require("../../src/db/mongo2");
4
- const mongodb_1 = require("mongodb");
5
- jest.mock('mongodb');
6
- const mockDb = {
7
- collection: jest.fn()
8
- };
9
- const mockConnect = jest.fn();
10
- const mockClient = {
11
- connect: mockConnect,
12
- db: jest.fn().mockReturnValue(mockDb)
13
- };
14
- beforeEach(() => {
15
- jest.clearAllMocks();
16
- mongodb_1.MongoClient.mockImplementation(() => mockClient);
17
- });
18
- describe('Mongo Utils', () => {
19
- it('should connect to MongoDB and store client', async () => {
20
- await (0, mongo2_1.connectToMongo2)('mongo-uri');
21
- expect(mockConnect).toHaveBeenCalled();
22
- });
23
- it('should return a Db instance when client is initialized', async () => {
24
- await (0, mongo2_1.connectToMongo2)('mongo-uri');
25
- const db = (0, mongo2_1.getDb2)('test-db');
26
- expect(mockClient.db).toHaveBeenCalledWith('test-db');
27
- expect(db).toBe(mockDb);
28
- });
29
- it('should return a collection when client is initialized', async () => {
30
- await (0, mongo2_1.connectToMongo2)('mongo-uri');
31
- (0, mongo2_1.getCollection2)('test-db', 'users');
32
- expect(mockClient.db).toHaveBeenCalledWith('test-db');
33
- expect(mockDb.collection).toHaveBeenCalledWith('users');
34
- });
35
- it('should throw error if client is not initialized (getDb)', () => {
36
- jest.isolateModules(() => {
37
- // eslint-disable-next-line @typescript-eslint/no-require-imports
38
- const { getDb2 } = require('../../src/db/mongo2');
39
- expect(() => getDb2('test-db')).toThrow('Mongo not initialized');
40
- });
41
- });
42
- it('should throw error if client is not initialized (getCollection)', () => {
43
- jest.isolateModules(() => {
44
- // eslint-disable-next-line @typescript-eslint/no-require-imports
45
- const { getCollection2 } = require('../../src/db/mongo2');
46
- expect(() => getCollection2('test-db', 'users')).toThrow('Mongo not initialized');
47
- });
48
- });
49
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,60 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const mongo3_1 = require("../../src/db/mongo3");
4
- const mongodb_1 = require("mongodb");
5
- jest.mock('mongodb');
6
- const mockDb = {
7
- collection: jest.fn()
8
- };
9
- const mockConnect = jest.fn();
10
- const mockClient = {
11
- connect: mockConnect,
12
- db: jest.fn().mockReturnValue(mockDb)
13
- };
14
- beforeEach(() => {
15
- jest.clearAllMocks();
16
- mongo3_1.__mongoClients.clear();
17
- mongo3_1.__connectPromises.clear();
18
- mongodb_1.MongoClient.mockImplementation(() => mockClient);
19
- });
20
- describe('MongoClientManager (multi-cluster)', () => {
21
- const clusterAUri = 'clusterA-uri';
22
- const clusterBUri = 'clusterB-uri';
23
- it('should connect and cache client for a single cluster', async () => {
24
- await (0, mongo3_1.connectToMongo3)(clusterAUri);
25
- expect(mockConnect).toHaveBeenCalled();
26
- const db = (0, mongo3_1.getDb3)(clusterAUri, 'test-db');
27
- expect(mockClient.db).toHaveBeenCalledWith('test-db');
28
- expect(db).toBe(mockDb);
29
- });
30
- it('should reuse client if already connected', async () => {
31
- await (0, mongo3_1.connectToMongo3)(clusterAUri);
32
- await (0, mongo3_1.connectToMongo3)(clusterAUri);
33
- expect(mockConnect).toHaveBeenCalledTimes(1);
34
- });
35
- it('should connect and cache separate clients for multiple clusters', async () => {
36
- await (0, mongo3_1.connectToMongo3)(clusterAUri);
37
- await (0, mongo3_1.connectToMongo3)(clusterBUri);
38
- expect(mockConnect).toHaveBeenCalledTimes(2);
39
- });
40
- it('should return a collection when client is initialized', async () => {
41
- await (0, mongo3_1.connectToMongo3)(clusterAUri);
42
- (0, mongo3_1.getCollection3)(clusterAUri, 'test-db', 'users');
43
- expect(mockClient.db).toHaveBeenCalledWith('test-db');
44
- expect(mockDb.collection).toHaveBeenCalledWith('users');
45
- });
46
- it('should throw error if client not initialized (getDb)', () => {
47
- jest.isolateModules(() => {
48
- // eslint-disable-next-line @typescript-eslint/no-require-imports
49
- const { getDb3 } = require('../../src/db/mongo3');
50
- expect(() => getDb3('unknown-uri', 'some-db')).toThrow('Mongo client not initialized');
51
- });
52
- });
53
- it('should throw error if client not initialized (getCollection)', () => {
54
- jest.isolateModules(() => {
55
- // eslint-disable-next-line @typescript-eslint/no-require-imports
56
- const { getCollection3 } = require('../../src/db/mongo3');
57
- expect(() => getCollection3('unknown-uri', 'some-db', 'users')).toThrow('Mongo client not initialized');
58
- });
59
- });
60
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,17 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const env_1 = require("../src/env");
4
- describe('getEnv', () => {
5
- it('returns the value of an existing env var', () => {
6
- process.env.TEST_KEY = 'test-value';
7
- expect((0, env_1.getEnv)('TEST_KEY')).toBe('test-value');
8
- });
9
- it('returns fallback if env var is not set', () => {
10
- delete process.env.OPTIONAL_KEY;
11
- expect((0, env_1.getEnv)('OPTIONAL_KEY', 'default')).toBe('default');
12
- });
13
- it('throws error if env var is not set and no fallback provided', () => {
14
- delete process.env.MISSING_KEY;
15
- expect(() => (0, env_1.getEnv)('MISSING_KEY')).toThrow('Missing env var MISSING_KEY');
16
- });
17
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,30 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const number_1 = require("../src/number");
4
- describe('round1', () => {
5
- it('rounds down correctly', () => {
6
- expect((0, number_1.round1)(4.21)).toBe(4.2);
7
- expect((0, number_1.round1)(4.24)).toBe(4.2);
8
- });
9
- it('rounds up correctly', () => {
10
- expect((0, number_1.round1)(4.25)).toBe(4.3);
11
- expect((0, number_1.round1)(4.26)).toBe(4.3);
12
- });
13
- it('handles floating point precision issues', () => {
14
- expect((0, number_1.round1)(1.005)).toBe(1.0); // classic float issue
15
- expect((0, number_1.round1)(2.675)).toBe(2.7);
16
- });
17
- it('handles negative numbers', () => {
18
- expect((0, number_1.round1)(-4.24)).toBe(-4.2);
19
- expect((0, number_1.round1)(-4.25)).toBe(-4.2); // JS rounds toward +∞ for halves
20
- expect((0, number_1.round1)(-4.26)).toBe(-4.3);
21
- });
22
- it('handles zero', () => {
23
- expect((0, number_1.round1)(0)).toBe(0);
24
- expect((0, number_1.round1)(0.04)).toBe(0);
25
- expect((0, number_1.round1)(0.05)).toBe(0.1);
26
- });
27
- it('handles large numbers', () => {
28
- expect((0, number_1.round1)(123456.789)).toBe(123456.8);
29
- });
30
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,24 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const src_1 = require("../src");
4
- describe('toNumber', () => {
5
- it('returns the same number when input is a finite number', () => {
6
- expect((0, src_1.toNumber)(123)).toBe(123);
7
- expect((0, src_1.toNumber)(0)).toBe(0);
8
- });
9
- it('returns number when input is a numeric string', () => {
10
- expect((0, src_1.toNumber)('456')).toBe(456);
11
- });
12
- it('returns null for non-numeric strings', () => {
13
- expect((0, src_1.toNumber)('abc')).toBeNull();
14
- expect((0, src_1.toNumber)('123abc')).toBeNull();
15
- expect((0, src_1.toNumber)('')).toBeNull();
16
- });
17
- it('returns null for non-numbers', () => {
18
- expect((0, src_1.toNumber)(NaN)).toBeNull();
19
- expect((0, src_1.toNumber)(Infinity)).toBeNull();
20
- expect((0, src_1.toNumber)(undefined)).toBeNull();
21
- expect((0, src_1.toNumber)(null)).toBeNull();
22
- expect((0, src_1.toNumber)({})).toBeNull();
23
- });
24
- });
@@ -1 +0,0 @@
1
- declare const path = "../src/pub";
@@ -1,102 +0,0 @@
1
- "use strict";
2
- // tests/pub.test.ts
3
- jest.mock('@google-cloud/pubsub', () => {
4
- const instances = [];
5
- class PubSub {
6
- constructor(opts) {
7
- this.topics = new Map();
8
- this.opts = opts;
9
- instances.push(this);
10
- }
11
- topic(name) {
12
- if (!this.topics.has(name)) {
13
- const publishMessage = jest.fn(({ data }) => Promise.resolve(`${this.opts?.projectId}-${name}`));
14
- this.topics.set(name, { publishMessage });
15
- }
16
- return this.topics.get(name);
17
- }
18
- }
19
- return { PubSub, __instances: instances };
20
- });
21
- const path = '../src/pub';
22
- describe('publishMessage', () => {
23
- beforeEach(() => {
24
- // ensure fresh module state between tests
25
- jest.resetModules();
26
- // clear any existing mock instances array if present
27
- try {
28
- const mockPubsub = require('@google-cloud/pubsub');
29
- if (mockPubsub && Array.isArray(mockPubsub.__instances)) {
30
- mockPubsub.__instances.length = 0;
31
- }
32
- }
33
- catch {
34
- // ignore if not loaded yet
35
- }
36
- });
37
- test('publishes and returns messageId, sends JSON buffer', async () => {
38
- const mockPubsub = require('@google-cloud/pubsub');
39
- const { publishMessage } = require(path);
40
- const envelope = { hello: 'world' };
41
- const msgId = await publishMessage('project-1', 'topic-a', envelope);
42
- expect(msgId).toBe('project-1-topic-a');
43
- const instance = mockPubsub.__instances[0];
44
- expect(instance).toBeDefined();
45
- const publishMock = instance.topics.get('topic-a').publishMessage;
46
- expect(publishMock).toHaveBeenCalledTimes(1);
47
- const callArg = publishMock.mock.calls[0][0];
48
- expect(callArg).toHaveProperty('data');
49
- expect(callArg.data.toString()).toBe(JSON.stringify(envelope));
50
- });
51
- test('throws on missing arguments', async () => {
52
- const { publishMessage } = require(path);
53
- await expect(publishMessage('', 't', {})).rejects.toThrow('projectId is required');
54
- await expect(publishMessage('p', '', {})).rejects.toThrow('topicName is required');
55
- await expect(publishMessage('p', 't', undefined)).rejects.toThrow('envelope is required');
56
- });
57
- test('caches one PubSub instance across multiple calls for the same project', async () => {
58
- const mockPubsub = require('@google-cloud/pubsub');
59
- const { publishMessage } = require(path);
60
- await publishMessage('project-1', 'topic-x', { a: 1 });
61
- await publishMessage('project-1', 'topic-x', { b: 2 });
62
- const instances = mockPubsub.__instances;
63
- expect(instances.length).toBe(1);
64
- const publishMock = instances[0].topics.get('topic-x').publishMessage;
65
- expect(publishMock).toHaveBeenCalledTimes(2);
66
- });
67
- test('reuses the same PubSub instance even when called with a different projectId', async () => {
68
- const mockPubsub = require('@google-cloud/pubsub');
69
- const { publishMessage } = require(path);
70
- // first call creates instance with project-A
71
- await publishMessage('project-A', 't1', { x: 1 });
72
- // second call passes a different project id but module currently reuses the cached instance
73
- await publishMessage('project-B', 't2', { y: 2 });
74
- const instances = mockPubsub.__instances;
75
- // because src/pub.ts caches a single PubSub instance, only one instance should exist
76
- expect(instances.length).toBe(1);
77
- // the created instance was constructed with the first project id
78
- expect(instances[0].opts).toEqual({ projectId: 'project-A' });
79
- // ensure both publishes were invoked on the same instance (different topics)
80
- expect(instances[0].topics.get('t1').publishMessage).toHaveBeenCalledTimes(1);
81
- expect(instances[0].topics.get('t2').publishMessage).toHaveBeenCalledTimes(1);
82
- });
83
- test('logs error and rethrows when publish fails', async () => {
84
- const mockPubsub = require('@google-cloud/pubsub');
85
- // Override the mock PubSub.topic to return a publishMessage that rejects
86
- mockPubsub.PubSub.prototype.topic = function (name) {
87
- if (!this.topics.has(name)) {
88
- const publishMessage = jest.fn(() => Promise.reject(new Error('boom')));
89
- this.topics.set(name, { publishMessage });
90
- }
91
- return this.topics.get(name);
92
- };
93
- const { publishMessage } = require(path);
94
- const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => { });
95
- await expect(publishMessage('project-err', 'topic-err', { fail: true })).rejects.toThrow('boom');
96
- expect(consoleErrorSpy).toHaveBeenCalled();
97
- const firstArg = consoleErrorSpy.mock.calls[0][0];
98
- expect(typeof firstArg).toBe('string');
99
- expect(firstArg).toContain('ERROR: publish failed:');
100
- consoleErrorSpy.mockRestore();
101
- });
102
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,60 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- // tests/regex.test.ts
4
- const regex_1 = require("../src/regex");
5
- describe('escapeForRegex', () => {
6
- it('escapes regex special characters (including backslash)', () => {
7
- const input = 'Pikachu.$^*+?()[]{}|\\';
8
- const expected = 'Pikachu\\.\\$\\^\\*\\+\\?\\(\\)\\[\\]\\{\\}\\|\\\\';
9
- expect((0, regex_1.escapeForRegex)(input)).toBe(expected);
10
- });
11
- it('replaces whitespace runs with \\s+ and escapes other metachars', () => {
12
- const input = 'Charizard (Holo Rare)'; // multiple spaces inside
13
- const expected = 'Charizard\\s+\\(Holo\\s+Rare\\)';
14
- expect((0, regex_1.escapeForRegex)(input)).toBe(expected);
15
- });
16
- it('leaves plain alphanumerics unchanged', () => {
17
- const input = 'Charmander123';
18
- expect((0, regex_1.escapeForRegex)(input)).toBe('Charmander123');
19
- });
20
- it('converts tabs and single spaces to \\s+ and escapes dots', () => {
21
- const input = 'Lt. Surge\tPikachu';
22
- const expected = 'Lt\\.\\s+Surge\\s+Pikachu';
23
- expect((0, regex_1.escapeForRegex)(input)).toBe(expected);
24
- });
25
- it('truncates input when maxLength is passed', () => {
26
- const long = 'a'.repeat(200);
27
- // override maxLength to 50 for this test
28
- expect((0, regex_1.escapeForRegex)(long, 50)).toBe('a'.repeat(50));
29
- });
30
- it('applies default cap of 100 characters when input is longer and contains no metachars', () => {
31
- const long = 'b'.repeat(150);
32
- const out = (0, regex_1.escapeForRegex)(long); // default cap = 100
33
- expect(out).toBe('b'.repeat(100));
34
- expect(out.length).toBe(100);
35
- });
36
- it('handles empty string', () => {
37
- expect((0, regex_1.escapeForRegex)('')).toBe('');
38
- });
39
- // -----------------------------
40
- // NEW: coverage for safeStr branch
41
- // -----------------------------
42
- it('handles undefined input (covers input ?? "")', () => {
43
- // call with undefined; TypeScript may complain so cast to any in test
44
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
- expect((0, regex_1.escapeForRegex)(undefined)).toBe('');
46
- });
47
- it('handles null input (covers input ?? "")', () => {
48
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
49
- expect((0, regex_1.escapeForRegex)(null)).toBe('');
50
- });
51
- it('coerces non-string input to string and escapes metachars if present', () => {
52
- // number becomes "42"
53
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
54
- expect((0, regex_1.escapeForRegex)(42)).toBe('42');
55
- // object coerces to "[object Object]" and special chars will be escaped if present
56
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
57
- const objInput = { toString: () => 'X(1) Y' };
58
- expect((0, regex_1.escapeForRegex)(objInput)).toBe('X\\(1\\)\\s+Y');
59
- });
60
- });
@@ -1 +0,0 @@
1
- export {};